From 4312599d5e46109e2c7161978c33808c6feb861c Mon Sep 17 00:00:00 2001 From: Jennifer Echenim Date: Sat, 28 Sep 2024 00:07:06 +0400 Subject: [PATCH 01/10] Update 404 component with default values --- packages/ui/components/common/404.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ui/components/common/404.tsx b/packages/ui/components/common/404.tsx index bf622202c0..599d7fd0bc 100644 --- a/packages/ui/components/common/404.tsx +++ b/packages/ui/components/common/404.tsx @@ -3,12 +3,12 @@ import CustomError from "./error"; export function Custom404Error({ customPageTitle, - showRedirectText, - redirectText, + showRedirectText = true, + redirectText = "Home Page", isFullWidth, message, showMessage = true, - redirectLink, + redirectLink = "/", children, }: ErrorType) { return ( @@ -19,7 +19,7 @@ export function Custom404Error({ } you're looking for.`} statusCode={404} showRedirectText={showRedirectText} - redirectText={redirectText || "Home Page"} + redirectText={redirectText} message={ message || `The ${ From caed604f1774ac9651d894150bda061d911e1174 Mon Sep 17 00:00:00 2001 From: Jennifer Echenim Date: Sat, 28 Sep 2024 00:13:00 +0400 Subject: [PATCH 02/10] Update package dependencies --- pnpm-lock.yaml | 8 ++++---- tools/tenscan/frontend/package.json | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddbd0cce6a..94ef13a2b5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -291,10 +291,10 @@ importers: specifier: workspace:* version: link:../../../packages/ui '@types/node': - specifier: ^20 + specifier: ^20.12.12 version: 20.12.12 '@types/react': - specifier: ^18 + specifier: ^18.3.3 version: 18.3.3 '@types/react-dom': specifier: ^18 @@ -315,7 +315,7 @@ importers: specifier: ^3.4.3 version: 3.4.3(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5)) typescript: - specifier: ^5 + specifier: ^5.4.5 version: 5.4.5 tools/walletextension/frontend: @@ -7534,7 +7534,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 diff --git a/tools/tenscan/frontend/package.json b/tools/tenscan/frontend/package.json index cf451ae918..252d566f6b 100644 --- a/tools/tenscan/frontend/package.json +++ b/tools/tenscan/frontend/package.json @@ -32,14 +32,14 @@ }, "devDependencies": { "@repo/ui": "workspace:*", - "@types/node": "^20", - "@types/react": "^18", + "@types/node": "^20.12.12", + "@types/react": "^18.3.3", "@types/react-dom": "^18", "autoprefixer": "^10.0.1", "eslint": "^8", "eslint-config-next": "14.0.1", "postcss": "^8", "tailwindcss": "^3.4.3", - "typescript": "^5" + "typescript": "^5.4.5" } } From 49f2284273acc2c3b870f855872f934c901c44a1 Mon Sep 17 00:00:00 2001 From: Jennifer Echenim Date: Sat, 28 Sep 2024 04:59:00 +0400 Subject: [PATCH 03/10] feat: page links' variables update details' pages --- .../batch/txs/{[fullHash].tsx => [hash].tsx} | 30 ++- .../tenscan/frontend/pages/batches/index.tsx | 12 +- tools/tenscan/frontend/pages/blocks/index.tsx | 9 +- .../{tx/personal => personal/tx}/[hash].tsx | 0 .../tenscan/frontend/pages/rollups/index.tsx | 12 +- .../frontend/pages/transactions/index.tsx | 17 +- .../src/components/health-indicator.tsx | 2 +- .../src/components/layouts/header.tsx | 2 - .../modules/batches/batch-hash-details.tsx | 173 +++++++++------ .../modules/batches/batch-height-details.tsx | 73 +++++-- .../components/modules/batches/columns.tsx | 22 +- .../modules/batches/transaction-columns.tsx | 6 +- .../src/components/modules/blocks/columns.tsx | 11 +- .../components/modules/dashboard/index.tsx | 30 ++- .../modules/dashboard/recent-batches.tsx | 10 +- .../modules/dashboard/recent-rollups.tsx | 4 +- .../modules/dashboard/recent-transactions.tsx | 10 +- .../components/modules/personal/columns.tsx | 40 ++-- .../src/components/modules/personal/index.tsx | 12 +- .../modules/personal/personal-txn-details.tsx | 203 ++++++++++-------- .../components/modules/rollups/columns.tsx | 21 +- .../modules/rollups/rollup-details.tsx | 45 +++- .../modules/transactions/columns.tsx | 6 +- .../transactions/transaction-details.tsx | 20 +- tools/tenscan/frontend/src/routes/index.ts | 61 ++++-- .../src/services/useBatchesService.ts | 2 +- .../frontend/src/services/useBlocksService.ts | 2 +- .../src/services/useRollupsService.ts | 2 +- .../src/services/useTransactionsService.ts | 2 +- 29 files changed, 524 insertions(+), 315 deletions(-) rename tools/tenscan/frontend/pages/batch/txs/{[fullHash].tsx => [hash].tsx} (66%) rename tools/tenscan/frontend/pages/{tx/personal => personal/tx}/[hash].tsx (100%) diff --git a/tools/tenscan/frontend/pages/batch/txs/[fullHash].tsx b/tools/tenscan/frontend/pages/batch/txs/[hash].tsx similarity index 66% rename from tools/tenscan/frontend/pages/batch/txs/[fullHash].tsx rename to tools/tenscan/frontend/pages/batch/txs/[hash].tsx index 805d969d9c..4de42bc959 100644 --- a/tools/tenscan/frontend/pages/batch/txs/[fullHash].tsx +++ b/tools/tenscan/frontend/pages/batch/txs/[hash].tsx @@ -14,15 +14,17 @@ import { import { useQuery } from "@tanstack/react-query"; import { useRouter } from "next/router"; import { getOptions } from "../../../src/lib/constants"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export default function BatchTransactions() { const router = useRouter(); - const { fullHash } = router.query; + const { hash } = router.query; const options = getOptions(router.query); const { data, isLoading, refetch } = useQuery({ - queryKey: ["batchTransactions", { fullHash, options }], - queryFn: () => fetchBatchTransactions(fullHash as string, options), + queryKey: ["batchTransactions", { hash, options }], + queryFn: () => fetchBatchTransactions(hash as string, options), }); const { TransactionsData, Total } = data?.result || { @@ -35,14 +37,20 @@ export default function BatchTransactions() { Transactions - -

Overview of all transactions in this batch:

- -
+
+ + + Overview of all transactions in this batch: + + + +
{ - setNoPolling(true); - - return () => { - setNoPolling(false); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const firstBatchHeight = Number(getItem(BatchesData, "height")); const lastBatchHeight = Number( getItem(BatchesData, "height", ItemPosition.LAST) diff --git a/tools/tenscan/frontend/pages/blocks/index.tsx b/tools/tenscan/frontend/pages/blocks/index.tsx index 996df2b082..4383266fe3 100644 --- a/tools/tenscan/frontend/pages/blocks/index.tsx +++ b/tools/tenscan/frontend/pages/blocks/index.tsx @@ -15,19 +15,12 @@ export const metadata: Metadata = { }; export default function Blocks() { - const { blocks, setNoPolling, refetchBlocks, isBlocksLoading } = - useBlocksService(); + const { blocks, refetchBlocks, isBlocksLoading } = useBlocksService(); const { BlocksData, Total } = blocks?.result || { BlocksData: [], Total: 0, }; - React.useEffect(() => { - setNoPolling(true); - return () => setNoPolling(false); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const firstBlockNumber = Number(getItem(BlocksData, "blockHeader.number")); const lastBlockNumber = Number( getItem(BlocksData, "blockHeader.number", ItemPosition.LAST) diff --git a/tools/tenscan/frontend/pages/tx/personal/[hash].tsx b/tools/tenscan/frontend/pages/personal/tx/[hash].tsx similarity index 100% rename from tools/tenscan/frontend/pages/tx/personal/[hash].tsx rename to tools/tenscan/frontend/pages/personal/tx/[hash].tsx diff --git a/tools/tenscan/frontend/pages/rollups/index.tsx b/tools/tenscan/frontend/pages/rollups/index.tsx index c41fb0ae67..7d8b6a19d1 100644 --- a/tools/tenscan/frontend/pages/rollups/index.tsx +++ b/tools/tenscan/frontend/pages/rollups/index.tsx @@ -15,22 +15,12 @@ export const metadata: Metadata = { }; export default function Rollups() { - const { rollups, setNoPolling, isRollupsLoading, refetchRollups } = - useRollupsService(); + const { rollups, isRollupsLoading, refetchRollups } = useRollupsService(); const { RollupsData, Total } = rollups?.result || { RollupsData: [], Total: 0, }; - React.useEffect(() => { - setNoPolling(true); - - return () => { - setNoPolling(false); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const firstRollupID = Number(getItem(RollupsData, "ID")); const lastRollupID = Number(getItem(RollupsData, "ID", ItemPosition.LAST)); diff --git a/tools/tenscan/frontend/pages/transactions/index.tsx b/tools/tenscan/frontend/pages/transactions/index.tsx index aba6a98503..5225b70d3d 100644 --- a/tools/tenscan/frontend/pages/transactions/index.tsx +++ b/tools/tenscan/frontend/pages/transactions/index.tsx @@ -15,26 +15,13 @@ export const metadata: Metadata = { }; export default function Transactions() { - const { - transactions, - refetchTransactions, - setNoPolling, - isTransactionsLoading, - } = useTransactionsService(); + const { transactions, refetchTransactions, isTransactionsLoading } = + useTransactionsService(); const { TransactionsData, Total } = transactions?.result || { TransactionsData: [], Total: 0, }; - React.useEffect(() => { - setNoPolling(true); - - return () => { - setNoPolling(false); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const firstBatchHeight = getItem(TransactionsData, "BatchHeight"); const lastBatchHeight = getItem( TransactionsData, diff --git a/tools/tenscan/frontend/src/components/health-indicator.tsx b/tools/tenscan/frontend/src/components/health-indicator.tsx index 20ee4deb24..c522ac2a5d 100644 --- a/tools/tenscan/frontend/src/components/health-indicator.tsx +++ b/tools/tenscan/frontend/src/components/health-indicator.tsx @@ -1,7 +1,7 @@ import React from "react"; import { Badge, badgeVariants } from "@repo/ui/components/shared/badge"; import { useGeneralService } from "../services/useGeneralService"; -import { BarChart } from "lucide-react"; +import { BarChart } from "@repo/ui/components/shared/react-icons"; import { TooltipProvider, TooltipTrigger, diff --git a/tools/tenscan/frontend/src/components/layouts/header.tsx b/tools/tenscan/frontend/src/components/layouts/header.tsx index c76b5f193f..b473e027c5 100644 --- a/tools/tenscan/frontend/src/components/layouts/header.tsx +++ b/tools/tenscan/frontend/src/components/layouts/header.tsx @@ -19,7 +19,6 @@ export default function Header() { width={150} height={40} className="cursor-pointer dark:hidden" - fetchPriority="auto" />
diff --git a/tools/tenscan/frontend/src/components/modules/batches/batch-hash-details.tsx b/tools/tenscan/frontend/src/components/modules/batches/batch-hash-details.tsx index 6dd9d2e57c..159d9b146d 100644 --- a/tools/tenscan/frontend/src/components/modules/batches/batch-hash-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/batches/batch-hash-details.tsx @@ -1,11 +1,15 @@ +import { useMemo, useState } from "react"; import { Separator } from "@repo/ui/components/shared/separator"; import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import KeyValueItem, { KeyValueList, } from "@repo/ui/components/shared/key-value"; -import { formatNumber, formatTimeAgo } from "@repo/ui/lib/utils"; +import { + formatNumber, + formatTimeAgo, + formatTimestampToDate, +} from "@repo/ui/lib/utils"; import { Badge } from "@repo/ui/components/shared/badge"; -import { BatchDetails } from "@/src/types/interfaces/BatchInterfaces"; import Link from "next/link"; import { EyeClosedIcon, @@ -15,13 +19,15 @@ import { Button } from "@repo/ui/components/shared/button"; import Copy from "@repo/ui/components/common/copy"; import { useRollupsService } from "@/src/services/useRollupsService"; import JSONPretty from "react-json-pretty"; -import { useState } from "react"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@repo/ui/components/shared/tooltip"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; +import { BatchDetails } from "@/src/types/interfaces/BatchInterfaces"; export function BatchHashDetailsComponent({ batchDetails, @@ -31,6 +37,31 @@ export function BatchHashDetailsComponent({ const { decryptedRollup, decryptEncryptedData } = useRollupsService(); const [showDecryptedData, setShowDecryptedData] = useState(false); + const transactionHashes = useMemo( + () => + batchDetails?.TxHashes.length > 0 ? ( +
    + {batchDetails.TxHashes.map((txHash, index) => ( +
  • + +
  • + ))} +
+ ) : ( + "-" + ), + [batchDetails?.TxHashes] + ); + + const handleDecryptToggle = () => { + decryptEncryptedData({ StrData: batchDetails?.EncryptedTxBlob }); + setShowDecryptedData(!showDecryptedData); + }; + return (
@@ -38,7 +69,9 @@ export function BatchHashDetailsComponent({ label="Batch Height" value={ {"#" + Number(batchDetails?.Header?.number)} @@ -47,47 +80,75 @@ export function BatchHashDetailsComponent({ /> } + value={ + + } /> + } /> } + value={ + + } /> } /> + } /> - {formatTimeAgo(batchDetails?.Header?.timestamp)} + + {formatTimeAgo(batchDetails?.Header?.timestamp) + + " - " + + formatTimestampToDate(batchDetails?.Header?.timestamp)} } /> } + value={ + + } /> + {formatNumber(batchDetails?.Header?.gasLimit)} + + } /> + {formatNumber(batchDetails?.Header?.baseFeePerGas)} + + } /> } /> @@ -111,73 +177,54 @@ export function BatchHashDetailsComponent({ /> } - /> - + } /> - - - + - {batchDetails?.TxHashes?.map((txHash, index) => ( -
  • - -
  • - ))} - - ) : ( - "-" - ) - } + value={transactionHashes} isLastItem />
    + +
    - {" "} + - {showDecryptedData && decryptedRollup ? ( + + {showDecryptedData && decryptedRollup && ( @@ -188,14 +235,14 @@ export function BatchHashDetailsComponent({ - ) : null} + )}
    - {decryptedRollup && showDecryptedData ? ( + {showDecryptedData && decryptedRollup && ( <> - ) : null} + )} } isLastItem diff --git a/tools/tenscan/frontend/src/components/modules/batches/batch-height-details.tsx b/tools/tenscan/frontend/src/components/modules/batches/batch-height-details.tsx index 81f37e3c28..4c58f4654f 100644 --- a/tools/tenscan/frontend/src/components/modules/batches/batch-height-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/batches/batch-height-details.tsx @@ -3,7 +3,11 @@ import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import KeyValueItem, { KeyValueList, } from "@repo/ui/components/shared/key-value"; -import { formatNumber, formatTimeAgo } from "@repo/ui/lib/utils"; +import { + formatNumber, + formatTimeAgo, + formatTimestampToDate, +} from "@repo/ui/lib/utils"; import { Badge } from "@repo/ui/components/shared/badge"; import { Batch } from "@/src/types/interfaces/BatchInterfaces"; import Link from "next/link"; @@ -14,13 +18,15 @@ import { import { Button } from "@repo/ui/components/shared/button"; import { useRollupsService } from "@/src/services/useRollupsService"; import JSONPretty from "react-json-pretty"; -import { useState } from "react"; +import React, { useState } from "react"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@repo/ui/components/shared/tooltip"; +import { pageLinks } from "@/src/routes"; +import { pathToUrl } from "@/src/routes/router"; export function BatchHeightDetailsComponent({ batchDetails, @@ -46,45 +52,67 @@ export function BatchHeightDetailsComponent({ value={ } /> + } /> } + value={ + + } /> } /> + } /> - {formatTimeAgo(batchDetails?.header?.timestamp)} + {formatTimeAgo(batchDetails?.header?.timestamp) + + " - " + + formatTimestampToDate(batchDetails?.header?.timestamp)} } /> } + value={ + + } /> } /> @@ -120,7 +149,12 @@ export function BatchHeightDetailsComponent({ /> } + value={ + + } /> - {batchDetails?.txCount || "-"} - + batchDetails?.txCount > 0 ? ( + + {batchDetails?.txCount}{" "} + + View + + + ) : ( + batchDetails?.txCount || "-" + ) } isLastItem /> diff --git a/tools/tenscan/frontend/src/components/modules/batches/columns.tsx b/tools/tenscan/frontend/src/components/modules/batches/columns.tsx index bcfbd09e29..721d15b5b2 100644 --- a/tools/tenscan/frontend/src/components/modules/batches/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/batches/columns.tsx @@ -8,6 +8,8 @@ import { formatNumber, formatTimeAgo } from "@repo/ui/lib/utils"; import { Batch } from "@/src/types/interfaces/BatchInterfaces"; import Link from "next/link"; import { Badge } from "@repo/ui/components/shared/badge"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export const columns: ColumnDef[] = [ { @@ -19,7 +21,9 @@ export const columns: ColumnDef[] = [ return (
    @@ -98,7 +102,9 @@ export const columns: ColumnDef[] = [ return ( ); }, @@ -124,7 +130,9 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { return ( {row.original.sequence} @@ -140,13 +148,17 @@ export const columns: ColumnDef[] = [ ), cell: ({ row }) => { - return ( + return row.original.txCount > 0 ? ( {row.original.txCount} + ) : ( + {row.original.txCount} ); }, enableSorting: false, diff --git a/tools/tenscan/frontend/src/components/modules/batches/transaction-columns.tsx b/tools/tenscan/frontend/src/components/modules/batches/transaction-columns.tsx index 760a7aaaa8..5ce0aa849b 100644 --- a/tools/tenscan/frontend/src/components/modules/batches/transaction-columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/batches/transaction-columns.tsx @@ -8,6 +8,8 @@ import { Transaction } from "@/src/types/interfaces/TransactionInterfaces"; import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import { formatTimeAgo } from "@repo/ui/lib/utils"; import Link from "next/link"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export const columns: ColumnDef[] = [ { @@ -37,7 +39,9 @@ export const columns: ColumnDef[] = [ return ( ); }, diff --git a/tools/tenscan/frontend/src/components/modules/blocks/columns.tsx b/tools/tenscan/frontend/src/components/modules/blocks/columns.tsx index c9cb165a6f..b7b04e657a 100644 --- a/tools/tenscan/frontend/src/components/modules/blocks/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/blocks/columns.tsx @@ -8,8 +8,9 @@ import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import { formatNumber, formatTimeAgo } from "@repo/ui/lib/utils"; import { Badge } from "@repo/ui/components/shared/badge"; import ExternalLink from "@repo/ui/components/shared/external-link"; -import { externalLinks } from "@/src/routes"; +import { externalPageLinks, pageLinks } from "@/src/routes"; import { EyeOpenIcon } from "@repo/ui/components/shared/react-icons"; +import { pathToUrl } from "@/src/routes/router"; export const columns: ColumnDef[] = [ { @@ -62,7 +63,9 @@ export const columns: ColumnDef[] = [ ) : ( ); }, @@ -152,7 +155,9 @@ export const columns: ColumnDef[] = [ const blockHeader = row.original.blockHeader as BlockHeader; return ( diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx index 7f839b2474..7726b6e769 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx @@ -30,6 +30,7 @@ import { BlocksIcon } from "@repo/ui/components/shared/react-icons"; import { useRollupsService } from "@/src/services/useRollupsService"; import { RecentRollups } from "./recent-rollups"; import { DashboardAnalyticsData } from "@/src/types/interfaces"; +import { pageLinks } from "@/src/routes"; interface RecentData { title: string; @@ -46,10 +47,29 @@ export default function Dashboard() { transactions, transactionCount, isTransactionCountLoading, + setNoPolling: setNoPollingTransactions, } = useTransactionsService(); const { contractCount, isContractCountLoading } = useContractsService(); - const { batches, latestBatch, isLatestBatchLoading } = useBatchesService(); - const { rollups } = useRollupsService(); + const { + batches, + latestBatch, + isLatestBatchLoading, + setNoPolling: setNoPollingBatches, + } = useBatchesService(); + const { rollups, setNoPolling: setNoPollingRollups } = useRollupsService(); + + React.useEffect(() => { + setNoPollingTransactions(false); + setNoPollingBatches(false); + setNoPollingRollups(false); + + return () => { + setNoPollingTransactions(true); + setNoPollingBatches(true); + setNoPollingRollups(true); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); const DASHBOARD_DATA = [ { @@ -118,21 +138,21 @@ export default function Dashboard() { title: "Recent Rollups", data: rollups, component: , - goTo: "/rollups", + goTo: pageLinks.rollups, className: "col-span-1 md:col-span-2 lg:col-span-3", }, { title: "Recent Batches", data: batches, component: , - goTo: "/batches", + goTo: pageLinks.batches, className: "col-span-1 md:col-span-2 lg:col-span-3", }, { title: "Recent Transactions", data: transactions, component: , - goTo: "/transactions", + goTo: pageLinks.transactions, className: "col-span-1 md:col-span-2 lg:col-span-3", }, ]; diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/recent-batches.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/recent-batches.tsx index 635a4ddc35..510ba09cae 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/recent-batches.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/recent-batches.tsx @@ -3,6 +3,8 @@ import { formatTimeAgo } from "@repo/ui/lib/utils"; import { Batch } from "@/src/types/interfaces/BatchInterfaces"; import { Avatar, AvatarFallback } from "@repo/ui/components/shared/avatar"; import Link from "next/link"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export function RecentBatches({ batches }: { batches: any }) { return ( @@ -15,7 +17,9 @@ export function RecentBatches({ batches }: { batches: any }) {

    #{Number(batch?.height)} @@ -28,7 +32,9 @@ export function RecentBatches({ batches }: { batches: any }) {

    diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/recent-rollups.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/recent-rollups.tsx index 2deb54cce6..1c1dd93dec 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/recent-rollups.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/recent-rollups.tsx @@ -2,6 +2,8 @@ import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import { formatTimeAgo } from "@repo/ui/lib/utils"; import { Avatar, AvatarFallback } from "@repo/ui/components/shared/avatar"; import { Rollup } from "@/src/types/interfaces/RollupInterfaces"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export function RecentRollups({ rollups }: { rollups: any }) { return ( @@ -22,7 +24,7 @@ export function RecentRollups({ rollups }: { rollups: any }) {
    diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/recent-transactions.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/recent-transactions.tsx index 63a90645d7..e94fc1b00d 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/recent-transactions.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/recent-transactions.tsx @@ -4,6 +4,8 @@ import { Transaction } from "@/src/types/interfaces/TransactionInterfaces"; import { Badge } from "@repo/ui/components/shared/badge"; import { formatTimeAgo } from "@repo/ui/lib/utils"; import Link from "next/link"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export function RecentTransactions({ transactions }: { transactions: any }) { return ( @@ -18,7 +20,9 @@ export function RecentTransactions({ transactions }: { transactions: any }) {

    Batch #{Number(transaction?.BatchHeight)} @@ -31,7 +35,9 @@ export function RecentTransactions({ transactions }: { transactions: any }) {

    diff --git a/tools/tenscan/frontend/src/components/modules/personal/columns.tsx b/tools/tenscan/frontend/src/components/modules/personal/columns.tsx index c6fc4fe06c..9dda107e44 100644 --- a/tools/tenscan/frontend/src/components/modules/personal/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/personal/columns.tsx @@ -8,8 +8,9 @@ import { DataTableColumnHeader } from "@repo/ui/components/common/data-table/dat import { PersonalTransactions } from "../../..//types/interfaces/TransactionInterfaces"; import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import { formatNumber } from "@repo/ui/lib/utils"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; import Link from "next/link"; -import { EyeOpenIcon } from "@repo/ui/components/shared/react-icons"; export const columns: ColumnDef[] = [ { @@ -19,11 +20,16 @@ export const columns: ColumnDef[] = [ ), cell: ({ row }) => { return ( -
    + #{Number(row.getValue("blockNumber"))} -
    + ); }, enableSorting: false, @@ -35,7 +41,14 @@ export const columns: ColumnDef[] = [ ), cell: ({ row }) => { - return ; + return ( + + ); }, enableSorting: false, enableHiding: false, @@ -46,7 +59,14 @@ export const columns: ColumnDef[] = [ ), cell: ({ row }) => { - return ; + return ( + + ); }, enableSorting: false, enableHiding: false, @@ -125,14 +145,4 @@ export const columns: ColumnDef[] = [ return value.includes(row.getValue(id)); }, }, - { - id: "actions", - cell: ({ row }) => { - return ( - - - - ); - }, - }, ]; diff --git a/tools/tenscan/frontend/src/components/modules/personal/index.tsx b/tools/tenscan/frontend/src/components/modules/personal/index.tsx index ba4a899736..948c0e4722 100644 --- a/tools/tenscan/frontend/src/components/modules/personal/index.tsx +++ b/tools/tenscan/frontend/src/components/modules/personal/index.tsx @@ -4,22 +4,12 @@ import { DataTable } from "@repo/ui/components/common/data-table/data-table"; import { useTransactionsService } from "@/src/services/useTransactionsService"; export default function PersonalTransactions() { - const { personalTxns, setNoPolling, personalTxnsLoading } = - useTransactionsService(); + const { personalTxns, personalTxnsLoading } = useTransactionsService(); const { Receipts, Total } = personalTxns || { Receipts: [], Total: 0, }; - React.useEffect(() => { - setNoPolling(true); - - return () => { - setNoPolling(false); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return ( <>
    diff --git a/tools/tenscan/frontend/src/components/modules/personal/personal-txn-details.tsx b/tools/tenscan/frontend/src/components/modules/personal/personal-txn-details.tsx index e4cd75306c..0e33d3225e 100644 --- a/tools/tenscan/frontend/src/components/modules/personal/personal-txn-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/personal/personal-txn-details.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import KeyValueItem, { KeyValueList, } from "@repo/ui/components/shared/key-value"; @@ -7,16 +7,21 @@ import { TransactionReceipt, TransactionType, } from "../../../types/interfaces/TransactionInterfaces"; -import Link from "next/link"; import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import { Badge } from "@repo/ui/components/shared/badge"; import { BadgeType } from "@repo/ui/lib/enums/badge"; +import { Button } from "@repo/ui/components/shared/button"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export function PersonalTxnDetailsComponent({ transactionDetails, }: { transactionDetails: TransactionReceipt; }) { + const [logsExpanded, setLogsExpanded] = useState(false); + const toggleLogs = () => setLogsExpanded(!logsExpanded); + const getTransactionType = (type: TransactionType) => { switch (type) { case PersonalTransactionType.Legacy: @@ -33,14 +38,16 @@ export function PersonalTxnDetailsComponent({ }; return ( -
    +
    } /> @@ -49,14 +56,16 @@ export function PersonalTxnDetailsComponent({ value={ } /> + {Number(transactionDetails?.transactionIndex)} } @@ -64,13 +73,7 @@ export function PersonalTxnDetailsComponent({ + {getTransactionType(transactionDetails?.type)} } @@ -89,27 +92,26 @@ export function PersonalTxnDetailsComponent({ } /> - + {Number(transactionDetails?.blockNumber)} - + } /> - {Number(transactionDetails?.gasUsed)}{" "} + + {Number(transactionDetails?.gasUsed)} } /> + {Number(transactionDetails?.cumulativeGasUsed)} } @@ -117,7 +119,7 @@ export function PersonalTxnDetailsComponent({ + {Number(transactionDetails?.effectiveGasPrice)} } @@ -133,10 +135,7 @@ export function PersonalTxnDetailsComponent({ + } /> } /> - 0 ? (
    - {transactionDetails?.logs.map((log, index) => ( -
    - - } - /> - } - /> - - } - /> - - + {logsExpanded + ? `Hide Logs (${transactionDetails.logs.length})` + : `Show Logs (${transactionDetails.logs.length})`} + + {logsExpanded && ( +
    + {transactionDetails?.logs.map((log, index) => ( +
    + + } + /> + } + /> + + } + /> + + + {log.removed ? "Yes" : "No"} + } - > - {log.removed ? "Yes" : "No"} - - } - /> - - {log.topics.map((topic, index) => ( -
    - } - /> + /> + + {log.topics.map((topic, index) => ( +
    + +
    + ))}
    - ))} -
    - } - /> - + + } + /> + + {Number(transactionDetails?.transactionIndex)} + + } + isLastItem /> - } - /> - - {Number(transactionDetails?.transactionIndex)} - - } - isLastItem - /> - + +
    + ))}
    - ))} + )}
    ) : ( - "No logs found" + "No logs found." ) } isLastItem diff --git a/tools/tenscan/frontend/src/components/modules/rollups/columns.tsx b/tools/tenscan/frontend/src/components/modules/rollups/columns.tsx index 37355e3d2a..429f4d6066 100644 --- a/tools/tenscan/frontend/src/components/modules/rollups/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/rollups/columns.tsx @@ -7,6 +7,8 @@ import { formatTimeAgo } from "@repo/ui/lib/utils"; import Link from "next/link"; import { EyeOpenIcon } from "@repo/ui/components/shared/react-icons"; import { Rollup } from "@/src/types/interfaces/RollupInterfaces"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export const columns: ColumnDef[] = [ { @@ -33,10 +35,9 @@ export const columns: ColumnDef[] = [ return ( ); }, @@ -80,7 +81,9 @@ export const columns: ColumnDef[] = [ return (
    @@ -102,7 +105,9 @@ export const columns: ColumnDef[] = [ return (
    @@ -119,7 +124,9 @@ export const columns: ColumnDef[] = [ id: "actions", cell: ({ row }) => { return ( - + ); diff --git a/tools/tenscan/frontend/src/components/modules/rollups/rollup-details.tsx b/tools/tenscan/frontend/src/components/modules/rollups/rollup-details.tsx index 2d6ae19fc1..239c6082c4 100644 --- a/tools/tenscan/frontend/src/components/modules/rollups/rollup-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/rollups/rollup-details.tsx @@ -2,9 +2,12 @@ import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import KeyValueItem, { KeyValueList, } from "@repo/ui/components/shared/key-value"; -import { formatTimeAgo } from "@repo/ui/lib/utils"; +import { formatTimeAgo, formatTimestampToDate } from "@repo/ui/lib/utils"; import Link from "next/link"; import { Rollup } from "@/src/types/interfaces/RollupInterfaces"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; +import { Badge } from "@repo/ui/components/shared/badge"; export function RollupDetailsComponent({ rollupDetails, @@ -17,14 +20,23 @@ export function RollupDetailsComponent({ + {formatTimeAgo(rollupDetails?.Timestamp) + + " - " + + formatTimestampToDate(rollupDetails?.Timestamp)} + + } /> } /> @@ -33,19 +45,26 @@ export function RollupDetailsComponent({ value={ } /> } + value={ + + } /> {"#" + rollupDetails?.FirstSeq} @@ -56,7 +75,9 @@ export function RollupDetailsComponent({ label="Last Batch Seq No." value={ {"#" + rollupDetails?.LastSeq} @@ -68,13 +89,17 @@ export function RollupDetailsComponent({ value={ } /> + } /> {"#" + msg.Sequence} diff --git a/tools/tenscan/frontend/src/components/modules/transactions/columns.tsx b/tools/tenscan/frontend/src/components/modules/transactions/columns.tsx index 3b103dd5e0..d09df4d386 100644 --- a/tools/tenscan/frontend/src/components/modules/transactions/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/transactions/columns.tsx @@ -9,6 +9,8 @@ import { Transaction } from "@/src/types/interfaces/TransactionInterfaces"; import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import { formatTimeAgo } from "@repo/ui/lib/utils"; import Link from "next/link"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export const columns: ColumnDef[] = [ { @@ -60,7 +62,9 @@ export const columns: ColumnDef[] = [ return ( ); }, diff --git a/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx b/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx index bc0eff4fee..953461a847 100644 --- a/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx @@ -2,11 +2,13 @@ import TruncatedAddress from "@repo/ui/components/common/truncated-address"; import KeyValueItem, { KeyValueList, } from "@repo/ui/components/shared/key-value"; -import { formatTimeAgo } from "@repo/ui/lib/utils"; +import { formatTimeAgo, formatTimestampToDate } from "@repo/ui/lib/utils"; import { BadgeType } from "@repo/ui/lib/enums/badge"; import { Badge } from "@repo/ui/components/shared/badge"; import { Transaction } from "@/src/types/interfaces/TransactionInterfaces"; import Link from "next/link"; +import { pathToUrl } from "@/src/routes/router"; +import { pageLinks } from "@/src/routes"; export function TransactionDetailsComponent({ transactionDetails, @@ -20,7 +22,9 @@ export function TransactionDetailsComponent({ label="Batch Height" value={ {"#" + Number(transactionDetails?.BatchHeight)} @@ -32,13 +36,21 @@ export function TransactionDetailsComponent({ value={ } /> + {formatTimeAgo(transactionDetails?.BatchTimestamp) + + " - " + + formatTimestampToDate(transactionDetails?.BatchTimestamp)} + + } /> { const { query } = useRouter(); - const [noPolling, setNoPolling] = useState(false); + const [noPolling, setNoPolling] = useState(true); const options = getOptions(query); diff --git a/tools/tenscan/frontend/src/services/useBlocksService.ts b/tools/tenscan/frontend/src/services/useBlocksService.ts index 1af7f9458d..97d318e313 100644 --- a/tools/tenscan/frontend/src/services/useBlocksService.ts +++ b/tools/tenscan/frontend/src/services/useBlocksService.ts @@ -7,7 +7,7 @@ import { useState } from "react"; export const useBlocksService = () => { const { query } = useRouter(); - const [noPolling, setNoPolling] = useState(false); + const [noPolling, setNoPolling] = useState(true); const options = getOptions(query); diff --git a/tools/tenscan/frontend/src/services/useRollupsService.ts b/tools/tenscan/frontend/src/services/useRollupsService.ts index eeb34e541c..2f1440ac4d 100644 --- a/tools/tenscan/frontend/src/services/useRollupsService.ts +++ b/tools/tenscan/frontend/src/services/useRollupsService.ts @@ -13,7 +13,7 @@ import { useRouter } from "next/router"; export const useRollupsService = () => { const { query } = useRouter(); - const [noPolling, setNoPolling] = useState(false); + const [noPolling, setNoPolling] = useState(true); const [decryptedRollup, setDecryptedRollup] = useState(); const options = getOptions(query); diff --git a/tools/tenscan/frontend/src/services/useTransactionsService.ts b/tools/tenscan/frontend/src/services/useTransactionsService.ts index 4fbc07265c..c507e9b256 100644 --- a/tools/tenscan/frontend/src/services/useTransactionsService.ts +++ b/tools/tenscan/frontend/src/services/useTransactionsService.ts @@ -18,7 +18,7 @@ export const useTransactionsService = () => { const { query } = useRouter(); const { address, provider } = useWalletStore(); - const [noPolling, setNoPolling] = useState(false); + const [noPolling, setNoPolling] = useState(true); const options = getOptions(query); From 5370ea293e2a9c2efe249a49ca234766d4566a02 Mon Sep 17 00:00:00 2001 From: Jennifer Echenim Date: Sat, 28 Sep 2024 05:39:19 +0400 Subject: [PATCH 04/10] refactor document page --- tools/tenscan/frontend/pages/docs/[id].tsx | 102 +++++++++++++++++---- 1 file changed, 86 insertions(+), 16 deletions(-) diff --git a/tools/tenscan/frontend/pages/docs/[id].tsx b/tools/tenscan/frontend/pages/docs/[id].tsx index df4ad880c1..a1b4da5f6a 100644 --- a/tools/tenscan/frontend/pages/docs/[id].tsx +++ b/tools/tenscan/frontend/pages/docs/[id].tsx @@ -1,35 +1,105 @@ import Layout from "@/src/components/layouts/default-layout"; +import { siteMetadata } from "@/src/lib/siteMetadata"; import { useRouter } from "next/router"; import React from "react"; -import DocumentComponent from "@repo/ui/components/common/document"; -import { useDocumentService } from "@repo/ui/services/useGeneralService"; -import EmptyState from "@repo/ui/components/common/empty-state"; -import { Button } from "@repo/ui/components/shared/button"; +import { showToast } from "@repo/ui/components/shared/use-toast"; +import { ToastType } from "@repo/ui/lib/enums/toast"; +import Custom404Error from "@repo/ui/components/common/404"; +import Spinner from "@repo/ui/components/shared/spinner"; -const DocumentPage = () => { - const { query, push } = useRouter(); - const { id } = query as { id: string }; +type Document = { + title: string; + subHeading: string; + content: { + heading: string; + content: string[]; + }[]; +}; + +const Document = () => { + const { query } = useRouter(); + const { id } = query; + + const [document, setDocument] = React.useState({} as Document); + const [loading, setLoading] = React.useState(false); + + const getDocument = async () => { + setLoading(true); + try { + const response = await fetch(`/docs/${id}.json`); + const data = await response.json(); + const processedData = { + title: data.title, + subHeading: data.subHeading, + content: data.content.map((item: any) => { + return { + heading: item.heading, + content: item.content.map((paragraph: any) => { + return paragraph.replace( + /siteMetadata.email/g, + siteMetadata.email + ); + }), + }; + }), + }; + setDocument(processedData); + } catch (error) { + showToast(ToastType.DESTRUCTIVE, "Error fetching document"); + } finally { + setLoading(false); + } + }; - const { data: document, isLoading } = useDocumentService(id); + React.useEffect(() => { + if (id) { + getDocument(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [id]); return (
    - {document ? ( - + {!loading ? ( + !document.title ? ( + + ) : ( + <> +
    +

    + {document.title} +

    +

    + {document.subHeading} +

    +
    +
    + {document.content && + document.content.map((section, index) => ( +
    +

    {section.heading}

    + {section.content && + section.content.map((paragraph, index) => ( +
    + ))} +
    + ))} +
    + + ) ) : ( - push("/")}>Go home} - /> + )}
    ); }; -export default DocumentPage; +export default Document; export async function getServerSideProps(context: any) { return { From 41b475fdc26f17ab20148ec5b3e5d4977bb206c0 Mon Sep 17 00:00:00 2001 From: Jennifer Echenim Date: Sat, 28 Sep 2024 05:46:09 +0400 Subject: [PATCH 05/10] fix: build error - duplicate import --- .../frontend/src/components/modules/dashboard/index.tsx | 2 +- .../frontend/src/components/modules/resources/decrypt.tsx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx index 7726b6e769..07ee091b50 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx @@ -11,6 +11,7 @@ import { ReaderIcon, CubeIcon, RocketIcon, + BlocksIcon, } from "@repo/ui/components/shared/react-icons"; import { RecentBatches } from "./recent-batches"; @@ -25,7 +26,6 @@ import AnalyticsCard from "./analytics-card"; import Link from "next/link"; import { cn, formatNumber } from "@repo/ui/lib/utils"; import { Badge } from "@repo/ui/components/shared/badge"; -import { BlocksIcon } from "@repo/ui/components/shared/react-icons"; import { useRollupsService } from "@/src/services/useRollupsService"; import { RecentRollups } from "./recent-rollups"; diff --git a/tools/tenscan/frontend/src/components/modules/resources/decrypt.tsx b/tools/tenscan/frontend/src/components/modules/resources/decrypt.tsx index ced6ba4cf4..a4379d7d08 100644 --- a/tools/tenscan/frontend/src/components/modules/resources/decrypt.tsx +++ b/tools/tenscan/frontend/src/components/modules/resources/decrypt.tsx @@ -14,8 +14,7 @@ import { } from "@repo/ui/components/shared/card"; import { Textarea } from "@repo/ui/components/shared/textarea"; import { currentEncryptedKey } from "@/src/lib/constants"; -import { CopyIcon } from "@repo/ui/components/shared/react-icons"; -import { Terminal } from "@repo/ui/components/shared/react-icons"; +import { CopyIcon, Terminal } from "@repo/ui/components/shared/react-icons"; import { useRouter } from "next/router"; import JSONPretty from "react-json-pretty"; import { useRollupsService } from "@/src/services/useRollupsService"; From 81bed71a2433e76b6456d30db9ef4967bfbb5c98 Mon Sep 17 00:00:00 2001 From: Jennifer Echenim Date: Sat, 28 Sep 2024 05:50:25 +0400 Subject: [PATCH 06/10] Update npm install to pnpm install --- tools/tenscan/frontend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tenscan/frontend/Dockerfile b/tools/tenscan/frontend/Dockerfile index 3e3b16a02f..87c2f5b785 100644 --- a/tools/tenscan/frontend/Dockerfile +++ b/tools/tenscan/frontend/Dockerfile @@ -4,6 +4,6 @@ RUN mkdir -p /home/obscuro/go-obscuro/tools/tenscan/ COPY ./tools/tenscan/frontend /home/obscuro/go-obscuro/tools/tenscan/frontend WORKDIR /home/obscuro/go-obscuro/tools/tenscan/frontend -RUN npm install +RUN pnpm install EXPOSE 80 \ No newline at end of file From 50376524979e8ec39f54ef9940aac815ebf640e9 Mon Sep 17 00:00:00 2001 From: Jennifer Echenim Date: Fri, 4 Oct 2024 14:51:11 +0400 Subject: [PATCH 07/10] Update Dockerfile for tenscan FE --- tools/tenscan/frontend/Dockerfile | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tools/tenscan/frontend/Dockerfile b/tools/tenscan/frontend/Dockerfile index 0760c0b4e1..1144273b25 100644 --- a/tools/tenscan/frontend/Dockerfile +++ b/tools/tenscan/frontend/Dockerfile @@ -1,11 +1,17 @@ FROM node:18-buster as runner -# Install pnpm + RUN npm install -g pnpm -# setup container data structure -RUN mkdir -p /home/obscuro/go-obscuro/tools/tenscan/ -COPY ./tools/tenscan/frontend /home/obscuro/go-obscuro/tools/tenscan/frontend -WORKDIR /home/obscuro/go-obscuro/tools/tenscan/frontend +COPY . /home/obscuro/go-obscuro/ + +WORKDIR /home/obscuro/go-obscuro/ + RUN pnpm install -EXPOSE 80 \ No newline at end of file +WORKDIR /home/obscuro/go-obscuro/tools/tenscan/frontend + +RUN pnpm install --filter ./tools/tenscan/frontend... + +EXPOSE 80 + +CMD ["pnpm", "run", "start"] From f1e60e21caa160d9cffd025a5cf6f5a639130aca Mon Sep 17 00:00:00 2001 From: Jennifer Echenim Date: Fri, 4 Oct 2024 15:33:46 +0400 Subject: [PATCH 08/10] fix: show full address on desktop --- .../components/modules/transactions/transaction-details.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx b/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx index 953461a847..dc9ab9aea8 100644 --- a/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx @@ -36,9 +36,7 @@ export function TransactionDetailsComponent({ value={ } /> From 8cff405f8d015bff1196bc0ccfa98c91fe5ff357 Mon Sep 17 00:00:00 2001 From: Jennifer Echenim Date: Tue, 8 Oct 2024 13:48:10 +0400 Subject: [PATCH 09/10] revert Tenscan changes --- tools/tenscan/frontend/Dockerfile | 17 +- tools/tenscan/frontend/api/batches.ts | 2 +- tools/tenscan/frontend/api/blocks.ts | 7 +- tools/tenscan/frontend/api/contracts.ts | 2 +- tools/tenscan/frontend/api/general.ts | 2 +- tools/tenscan/frontend/api/rollups.ts | 4 +- tools/tenscan/frontend/api/transactions.ts | 7 +- tools/tenscan/frontend/next.config.js | 1 - tools/tenscan/frontend/package.json | 27 ++- tools/tenscan/frontend/pages/404.tsx | 41 +++- tools/tenscan/frontend/pages/500.tsx | 35 ++- tools/tenscan/frontend/pages/_app.tsx | 19 +- tools/tenscan/frontend/pages/_error.tsx | 102 +++++++-- .../frontend/pages/address/[address].tsx | 8 +- tools/tenscan/frontend/pages/batch/[hash].tsx | 6 +- .../frontend/pages/batch/height/[height].tsx | 6 +- .../frontend/pages/batch/txs/[fullHash].tsx | 66 ++++++ .../frontend/pages/batch/txs/[hash].tsx | 75 ------ .../tenscan/frontend/pages/batches/index.tsx | 18 +- tools/tenscan/frontend/pages/blocks/index.tsx | 15 +- tools/tenscan/frontend/pages/docs/[id].tsx | 8 +- .../tenscan/frontend/pages/personal/index.tsx | 18 +- .../frontend/pages/rollup/[hash]/batches.tsx | 4 +- .../frontend/pages/rollup/[hash]/index.tsx | 10 +- .../rollup/batch/sequence/[sequence].tsx | 10 +- .../tenscan/frontend/pages/rollups/index.tsx | 18 +- .../frontend/pages/transactions/index.tsx | 23 +- tools/tenscan/frontend/pages/tx/[hash].tsx | 17 +- .../{personal/tx => tx/personal}/[hash].tsx | 25 +- .../src/components/date-range-picker.tsx | 10 +- .../frontend/src/components/head-seo.tsx | 2 +- .../src/components/health-indicator.tsx | 6 +- .../src/components/layouts/footer.tsx | 5 +- .../src/components/layouts/header.tsx | 15 +- .../frontend/src/components/main-nav.tsx | 8 +- .../frontend/src/components/mode-toggle.tsx | 40 ++++ .../modules/batches/batch-hash-details.tsx | 194 ++++++---------- .../modules/batches/batch-height-details.tsx | 94 ++------ .../components/modules/batches/columns.tsx | 30 +-- .../components/modules/batches/constants.tsx | 2 +- .../modules/batches/transaction-columns.tsx | 16 +- .../src/components/modules/blocks/columns.tsx | 23 +- .../components/modules/blocks/constants.tsx | 2 +- .../modules/common/connect-wallet.tsx | 43 ++++ .../src/components/modules/common/copy.tsx | 22 ++ .../data-table/data-table-column-header.tsx | 71 ++++++ .../data-table/data-table-faceted-filter.tsx | 147 ++++++++++++ .../data-table/data-table-pagination.tsx | 144 ++++++++++++ .../data-table/data-table-row-actions.tsx | 65 ++++++ .../common/data-table/data-table-toolbar.tsx | 68 ++++++ .../data-table/data-table-view-options.tsx | 59 +++++ .../modules/common/data-table/data-table.tsx | 211 +++++++++++++++++ .../common/data-table/skeleton-loader.tsx | 23 ++ .../components/modules/common/empty-state.tsx | 54 +++++ .../modules/common/network-status.tsx | 40 ++++ .../modules/common/truncated-address.tsx | 72 ++++++ .../modules/dashboard/analytics-card.tsx | 6 +- .../components/modules/dashboard/index.tsx | 47 ++-- .../modules/dashboard/recent-batches.tsx | 16 +- .../modules/dashboard/recent-rollups.tsx | 16 +- .../modules/dashboard/recent-transactions.tsx | 18 +- .../components/modules/personal/columns.tsx | 52 ++--- .../src/components/modules/personal/data.tsx | 2 +- .../src/components/modules/personal/index.tsx | 14 +- .../modules/personal/personal-txn-details.tsx | 214 ++++++++---------- .../components/modules/resources/decrypt.tsx | 21 +- .../verified-data/VerifiedContracts.tsx | 12 +- .../verified-data/VerifiedSequencerData.tsx | 12 +- .../components/modules/rollups/columns.tsx | 29 +-- .../components/modules/rollups/constants.tsx | 2 +- .../modules/rollups/rollup-details.tsx | 53 +---- .../modules/transactions/columns.tsx | 14 +- .../modules/transactions/constants.tsx | 2 +- .../transactions/transaction-details.tsx | 28 +-- .../components/providers/wallet-provider.tsx | 99 ++++++++ .../frontend/src/components/search.tsx | 2 +- .../frontend/src/components/ui/alert.tsx | 64 ++++++ .../frontend/src/components/ui/avatar.tsx | 54 +++++ .../frontend/src/components/ui/badge.tsx | 37 +++ .../frontend/src/components/ui/button.tsx | 58 +++++ .../frontend/src/components/ui/calendar.tsx | 62 +++++ .../frontend/src/components/ui/card.tsx | 56 +++++ .../frontend/src/components/ui/checkbox.tsx | 28 +++ .../frontend/src/components/ui/command.tsx | 153 +++++++++++++ .../frontend/src/components/ui/dialog.tsx | 102 +++++++++ .../src/components/ui/dropdown-menu.tsx | 183 +++++++++++++++ .../src/components/ui/external-link.tsx | 25 ++ .../frontend/src/components/ui/input.tsx | 24 ++ .../frontend/src/components/ui/key-value.tsx | 29 +++ .../frontend/src/components/ui/label.tsx | 19 ++ .../src/components/ui/navigation-menu.tsx | 120 ++++++++++ .../frontend/src/components/ui/popover.tsx | 29 +++ .../frontend/src/components/ui/select.tsx | 119 ++++++++++ .../frontend/src/components/ui/separator.tsx | 29 +++ .../frontend/src/components/ui/skeleton.tsx | 15 ++ .../frontend/src/components/ui/spinner.tsx | 11 + .../frontend/src/components/ui/table.tsx | 91 ++++++++ .../frontend/src/components/ui/tabs.tsx | 53 +++++ .../frontend/src/components/ui/textarea.tsx | 24 ++ .../frontend/src/components/ui/toast.tsx | 130 +++++++++++ .../frontend/src/components/ui/toaster.tsx | 33 +++ .../frontend/src/components/ui/tooltip.tsx | 28 +++ .../frontend/src/components/ui/use-toast.ts | 196 ++++++++++++++++ tools/tenscan/frontend/src/hooks/useCopy.ts | 59 +++++ tools/tenscan/frontend/src/lib/constants.ts | 7 + .../tenscan/frontend/src/lib/siteMetadata.ts | 4 +- tools/tenscan/frontend/src/lib/utils.ts | 55 +++++ tools/tenscan/frontend/src/routes/index.ts | 57 +---- .../src/services/useBatchesService.ts | 2 +- .../frontend/src/services/useBlocksService.ts | 2 +- .../src/services/useRollupsService.ts | 4 +- .../src/services/useTransactionsService.ts | 10 +- .../src/types/interfaces/BlockInterfaces.ts | 5 - .../src/types/interfaces/WalletInterfaces.ts | 4 + .../frontend/src/types/interfaces/index.ts | 86 +++++++ tools/tenscan/frontend/tailwind.config.js | 5 - tools/tenscan/frontend/tailwind.config.ts | 101 +++++++++ 117 files changed, 4015 insertions(+), 876 deletions(-) create mode 100644 tools/tenscan/frontend/pages/batch/txs/[fullHash].tsx delete mode 100644 tools/tenscan/frontend/pages/batch/txs/[hash].tsx rename tools/tenscan/frontend/pages/{personal/tx => tx/personal}/[hash].tsx (70%) create mode 100644 tools/tenscan/frontend/src/components/mode-toggle.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/connect-wallet.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/copy.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/data-table/data-table-column-header.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/data-table/data-table-faceted-filter.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/data-table/data-table-pagination.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/data-table/data-table-row-actions.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/data-table/data-table-toolbar.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/data-table/data-table-view-options.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/data-table/data-table.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/data-table/skeleton-loader.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/empty-state.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/network-status.tsx create mode 100644 tools/tenscan/frontend/src/components/modules/common/truncated-address.tsx create mode 100644 tools/tenscan/frontend/src/components/providers/wallet-provider.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/alert.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/avatar.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/badge.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/button.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/calendar.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/card.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/checkbox.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/command.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/dialog.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/dropdown-menu.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/external-link.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/input.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/key-value.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/label.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/navigation-menu.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/popover.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/select.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/separator.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/skeleton.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/spinner.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/table.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/tabs.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/textarea.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/toast.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/toaster.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/tooltip.tsx create mode 100644 tools/tenscan/frontend/src/components/ui/use-toast.ts create mode 100644 tools/tenscan/frontend/src/hooks/useCopy.ts create mode 100644 tools/tenscan/frontend/src/lib/utils.ts create mode 100644 tools/tenscan/frontend/tailwind.config.ts diff --git a/tools/tenscan/frontend/Dockerfile b/tools/tenscan/frontend/Dockerfile index 1144273b25..691489c28a 100644 --- a/tools/tenscan/frontend/Dockerfile +++ b/tools/tenscan/frontend/Dockerfile @@ -1,17 +1,12 @@ FROM node:18-buster as runner - +# Install pnpm RUN npm install -g pnpm - -COPY . /home/obscuro/go-obscuro/ - -WORKDIR /home/obscuro/go-obscuro/ - -RUN pnpm install +# setup container data structure +RUN mkdir -p /home/obscuro/go-obscuro/tools/tenscan/ +COPY ./tools/tenscan/frontend /home/obscuro/go-obscuro/tools/tenscan/frontend WORKDIR /home/obscuro/go-obscuro/tools/tenscan/frontend -RUN pnpm install --filter ./tools/tenscan/frontend... - -EXPOSE 80 +RUN pnpm install -CMD ["pnpm", "run", "start"] +EXPOSE 80 \ No newline at end of file diff --git a/tools/tenscan/frontend/api/batches.ts b/tools/tenscan/frontend/api/batches.ts index ce21899900..10ff925eaf 100644 --- a/tools/tenscan/frontend/api/batches.ts +++ b/tools/tenscan/frontend/api/batches.ts @@ -1,13 +1,13 @@ import { httpRequest } from "."; import { apiRoutes } from "@/src/routes"; import { pathToUrl } from "@/src/routes/router"; +import { ResponseDataInterface } from "@/src/types/interfaces"; import { Batch, BatchDetails, BatchResponse, LatestBatch, } from "@/src/types/interfaces/BatchInterfaces"; -import { ResponseDataInterface } from "@repo/ui/lib/types/common"; export const fetchBatches = async ( payload?: Record diff --git a/tools/tenscan/frontend/api/blocks.ts b/tools/tenscan/frontend/api/blocks.ts index 5ccefdcf00..0a4519c89e 100644 --- a/tools/tenscan/frontend/api/blocks.ts +++ b/tools/tenscan/frontend/api/blocks.ts @@ -1,13 +1,12 @@ import { httpRequest } from "."; import { apiRoutes } from "@/src/routes"; import { pathToUrl } from "@/src/routes/router"; -import { BlockResponse } from "@/src/types/interfaces/BlockInterfaces"; -import { ResponseDataInterface } from "@repo/ui/lib/types/common"; +import { ResponseDataInterface } from "@/src/types/interfaces"; export const fetchBlocks = async ( payload?: Record -): Promise> => { - return await httpRequest>({ +): Promise> => { + return await httpRequest>({ method: "get", url: pathToUrl(apiRoutes.getBlocks), searchParams: payload, diff --git a/tools/tenscan/frontend/api/contracts.ts b/tools/tenscan/frontend/api/contracts.ts index 79134ea44b..0ece0fc929 100644 --- a/tools/tenscan/frontend/api/contracts.ts +++ b/tools/tenscan/frontend/api/contracts.ts @@ -1,8 +1,8 @@ import { httpRequest } from "."; import { apiRoutes } from "@/src/routes"; import { pathToUrl } from "@/src/routes/router"; +import { ResponseDataInterface } from "@/src/types/interfaces"; import { ContractCount } from "@/src/types/interfaces/ContractInterface"; -import { ResponseDataInterface } from "@repo/ui/lib/types/common"; export const fetchContractCount = async ( payload?: Record diff --git a/tools/tenscan/frontend/api/general.ts b/tools/tenscan/frontend/api/general.ts index 5a1f5d0d84..a9e09941dc 100644 --- a/tools/tenscan/frontend/api/general.ts +++ b/tools/tenscan/frontend/api/general.ts @@ -1,4 +1,4 @@ -import { ResponseDataInterface } from "@repo/ui/lib/types/common"; +import { ResponseDataInterface } from "@/src/types/interfaces"; import { httpRequest } from "."; import { pathToUrl } from "@/src/routes/router"; import { apiRoutes } from "@/src/routes"; diff --git a/tools/tenscan/frontend/api/rollups.ts b/tools/tenscan/frontend/api/rollups.ts index 954ad2c50d..eddfc0ed12 100644 --- a/tools/tenscan/frontend/api/rollups.ts +++ b/tools/tenscan/frontend/api/rollups.ts @@ -1,8 +1,8 @@ import { httpRequest } from "."; import { apiRoutes } from "@/src/routes"; import { pathToUrl } from "@/src/routes/router"; -import { ResponseDataInterface } from "@repo/ui/lib/types/common"; -import { BatchResponse } from "@/src/types/interfaces/BatchInterfaces"; +import { ResponseDataInterface } from "@/src/types/interfaces"; +import { Batch, BatchResponse } from "@/src/types/interfaces/BatchInterfaces"; import { Rollup, RollupsResponse, diff --git a/tools/tenscan/frontend/api/transactions.ts b/tools/tenscan/frontend/api/transactions.ts index 9e8cebf2b3..051bf757ff 100644 --- a/tools/tenscan/frontend/api/transactions.ts +++ b/tools/tenscan/frontend/api/transactions.ts @@ -1,16 +1,15 @@ -import { jsonHexToObj } from "@repo/ui/lib/utils"; +import { jsonHexToObj } from "@/src/lib/utils"; import { httpRequest } from "."; import { apiRoutes, ethMethods, tenCustomQueryMethods } from "@/src/routes"; import { pathToUrl } from "@/src/routes/router"; +import { ResponseDataInterface, ToastType } from "@/src/types/interfaces"; import { TransactionCount, Price, TransactionResponse, Transaction, } from "@/src/types/interfaces/TransactionInterfaces"; -import { showToast } from "@repo/ui/components/shared/use-toast"; -import { ResponseDataInterface } from "@repo/ui/lib/types/common"; -import { ToastType } from "@repo/ui/lib/enums/toast"; +import { showToast } from "@/src/components/ui/use-toast"; export const fetchTransactions = async ( payload?: Record diff --git a/tools/tenscan/frontend/next.config.js b/tools/tenscan/frontend/next.config.js index 841789e9ae..50f8420725 100644 --- a/tools/tenscan/frontend/next.config.js +++ b/tools/tenscan/frontend/next.config.js @@ -1,7 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, - transpilePackages: ["@repo/ui"], images: { unoptimized: true, }, diff --git a/tools/tenscan/frontend/package.json b/tools/tenscan/frontend/package.json index 252d566f6b..87793b2534 100644 --- a/tools/tenscan/frontend/package.json +++ b/tools/tenscan/frontend/package.json @@ -10,6 +10,20 @@ "lint": "next lint" }, "dependencies": { + "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-navigation-menu": "^1.1.4", + "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-separator": "^1.0.3", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-toast": "^1.1.5", + "@radix-ui/react-tooltip": "^1.0.7", "@tanstack/react-query": "^5.8.1", "@tanstack/react-query-devtools": "^5.8.1", "@tanstack/react-table": "^8.10.7", @@ -19,6 +33,7 @@ "cmdk": "^0.2.0", "date-fns": "^2.30.0", "ethers": "^5.7.2", + "lucide-react": "^0.292.0", "next": "14.0.1", "next-themes": "^0.2.1", "path-to-regexp": "^6.2.1", @@ -28,18 +43,18 @@ "react-json-pretty": "^2.2.0", "recharts": "^2.9.3", "tailwind-merge": "^2.0.0", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^4.4.6" }, "devDependencies": { - "@repo/ui": "workspace:*", - "@types/node": "^20.12.12", - "@types/react": "^18.3.3", + "@types/node": "^20", + "@types/react": "^18", "@types/react-dom": "^18", "autoprefixer": "^10.0.1", "eslint": "^8", "eslint-config-next": "14.0.1", "postcss": "^8", - "tailwindcss": "^3.4.3", - "typescript": "^5.4.5" + "tailwindcss": "^3.3.0", + "typescript": "^5" } } diff --git a/tools/tenscan/frontend/pages/404.tsx b/tools/tenscan/frontend/pages/404.tsx index 52c795cc44..2b7a07c742 100644 --- a/tools/tenscan/frontend/pages/404.tsx +++ b/tools/tenscan/frontend/pages/404.tsx @@ -1,7 +1,38 @@ -import Custom404Error from "@repo/ui/components/common/404"; +import { ErrorType } from "@/src/types/interfaces"; +import Error from "./_error"; -const Custom404 = () => { - return ; -}; +export function Custom404Error({ + customPageTitle, + showRedirectText, + redirectText, + isFullWidth, + message, + showMessage = true, + redirectLink, + children, +}: ErrorType) { + return ( + + {children} + + ); +} -export default Custom404; +export default Custom404Error; diff --git a/tools/tenscan/frontend/pages/500.tsx b/tools/tenscan/frontend/pages/500.tsx index 62e6c09860..2f3826812c 100644 --- a/tools/tenscan/frontend/pages/500.tsx +++ b/tools/tenscan/frontend/pages/500.tsx @@ -1,7 +1,32 @@ -import Custom500Error from "@repo/ui/components/common/500"; +import { ErrorType } from "@/src/types/interfaces"; +import Error from "./_error"; -const Custom404 = () => { - return ; -}; +function Custom500Error({ + customPageTitle, + message, + showRedirectText, + redirectText, + err, + redirectLink, + children, +}: ErrorType) { + return ( + + {children} + + ); +} -export default Custom404; +export default Custom500Error; diff --git a/tools/tenscan/frontend/pages/_app.tsx b/tools/tenscan/frontend/pages/_app.tsx index 5074041570..9c63ee0a42 100644 --- a/tools/tenscan/frontend/pages/_app.tsx +++ b/tools/tenscan/frontend/pages/_app.tsx @@ -8,14 +8,15 @@ import { } from "@tanstack/react-query"; import "@/styles/globals.css"; import type { AppProps } from "next/app"; -import { Toaster } from "@repo/ui/components/shared/toaster"; -import { NetworkStatus } from "@repo/ui/components/common/network-status"; +import { Toaster } from "@/src/components/ui/toaster"; +import { WalletConnectionProvider } from "@/src/components/providers/wallet-provider"; +import { NetworkStatus } from "@/src/components/modules/common/network-status"; import HeadSeo from "@/src/components/head-seo"; import { siteMetadata } from "@/src/lib/siteMetadata"; import Script from "next/script"; import { GOOGLE_ANALYTICS_ID } from "@/src/lib/constants"; -import { showToast } from "@repo/ui/components/shared/use-toast"; -import { ToastType } from "@repo/ui/lib/enums/toast"; +import { showToast } from "@/src/components/ui/use-toast"; +import { ToastType } from "@/src/types/interfaces"; export default function App({ Component, pageProps }: AppProps) { const mutationCache = new MutationCache({ @@ -75,10 +76,12 @@ export default function App({ Component, pageProps }: AppProps) { enableSystem disableTransitionOnChange > - - - - + + + + + + diff --git a/tools/tenscan/frontend/pages/_error.tsx b/tools/tenscan/frontend/pages/_error.tsx index c0a556a211..54b7deca69 100644 --- a/tools/tenscan/frontend/pages/_error.tsx +++ b/tools/tenscan/frontend/pages/_error.tsx @@ -1,27 +1,91 @@ -import CustomError from "@repo/ui/components/common/error"; import React from "react"; +import NextErrorComponent from "next/error"; +import Link from "next/link"; +import Image from "next/image"; +import { ErrorType } from "@/src/types/interfaces"; -export default function CustomErrorPage({ statusCode, err }: any) { +function ErrorMessage({ + statusText, + message, + showMessage, + showStatusText, +}: any) { return ( - +
    + {showStatusText &&

    {statusText}

    } + {message && showMessage && ( +

    {message}

    + )} +
    ); } -// custom server-side props -CustomErrorPage.getInitialProps = async ({ res, err }: any) => { +export function CustomError({ + showRedirectText = true, + heading = "Oops! Something went wrong.", + statusText = "500", + message = "We're experiencing technical difficulties. Please try again later.", + redirectText = "Home Page", + isFullWidth, + err, + showMessage = true, + showStatusText, + statusCode, + isModal, + redirectLink = "/", + children, + ...props +}: ErrorType) { + return ( +
    +
    +
    +

    {heading}

    +
    + +
    + {showRedirectText && ( +
    + Go to{" "} + + {redirectText} + {" "} + {/*
    + Looks like you're on the wrong side of town, buddy. + Let's get you back on the right side. +
    */} +
    + )} + {children} +
    +
    +
    + ); +} + +CustomError.getInitialProps = async ({ res, err }: any) => { const statusCode = res ? res.statusCode : err?.statusCode || 404; - return { statusCode, err }; + const errorInitialProps = await NextErrorComponent.getInitialProps({ + res, + err, + } as any); + errorInitialProps.statusCode = statusCode; + + return statusCode < 500 + ? errorInitialProps + : { ...errorInitialProps, statusCode }; }; + +export default CustomError; diff --git a/tools/tenscan/frontend/pages/address/[address].tsx b/tools/tenscan/frontend/pages/address/[address].tsx index 05c70e86eb..32777aa68e 100644 --- a/tools/tenscan/frontend/pages/address/[address].tsx +++ b/tools/tenscan/frontend/pages/address/[address].tsx @@ -1,8 +1,10 @@ -import React from "react"; +import HeadSeo from "@/src/components/head-seo"; import Layout from "@/src/components/layouts/default-layout"; -import EmptyState from "@repo/ui/components/common/empty-state"; -import { Button } from "@repo/ui/components/shared/button"; +import EmptyState from "@/src/components/modules/common/empty-state"; +import { Button } from "@/src/components/ui/button"; +import { siteMetadata } from "@/src/lib/siteMetadata"; import { useRouter } from "next/router"; +import React from "react"; const AddressDetails = () => { const { push } = useRouter(); diff --git a/tools/tenscan/frontend/pages/batch/[hash].tsx b/tools/tenscan/frontend/pages/batch/[hash].tsx index bb6bac900a..cd55e6f65c 100644 --- a/tools/tenscan/frontend/pages/batch/[hash].tsx +++ b/tools/tenscan/frontend/pages/batch/[hash].tsx @@ -7,8 +7,8 @@ import { CardTitle, CardContent, CardDescription, -} from "@repo/ui/components/shared/card"; -import LoadingState from "@repo/ui/components/common/loading-state"; +} from "@/src/components/ui/card"; +import { Skeleton } from "@/src/components/ui/skeleton"; import { useQuery } from "@tanstack/react-query"; import { useRouter } from "next/router"; @@ -26,7 +26,7 @@ export default function Batch() { return ( {isLoading ? ( - + ) : batchDetails ? ( diff --git a/tools/tenscan/frontend/pages/batch/height/[height].tsx b/tools/tenscan/frontend/pages/batch/height/[height].tsx index f0624fb889..7982d825cf 100644 --- a/tools/tenscan/frontend/pages/batch/height/[height].tsx +++ b/tools/tenscan/frontend/pages/batch/height/[height].tsx @@ -1,14 +1,14 @@ import { fetchBatchByHeight } from "@/api/batches"; import Layout from "@/src/components/layouts/default-layout"; import { BatchHeightDetailsComponent } from "@/src/components/modules/batches/batch-height-details"; -import LoadingState from "@repo/ui/components/common/loading-state"; import { Card, CardHeader, CardTitle, CardContent, CardDescription, -} from "@repo/ui/components/shared/card"; +} from "@/src/components/ui/card"; +import { Skeleton } from "@/src/components/ui/skeleton"; import { useQuery } from "@tanstack/react-query"; import { useRouter } from "next/router"; @@ -26,7 +26,7 @@ export default function Batch() { return ( {isLoading ? ( - + ) : batchDetails ? ( diff --git a/tools/tenscan/frontend/pages/batch/txs/[fullHash].tsx b/tools/tenscan/frontend/pages/batch/txs/[fullHash].tsx new file mode 100644 index 0000000000..1d0748d532 --- /dev/null +++ b/tools/tenscan/frontend/pages/batch/txs/[fullHash].tsx @@ -0,0 +1,66 @@ +import { fetchBatchTransactions } from "@/api/batches"; +import Layout from "@/src/components/layouts/default-layout"; +import { DataTable } from "@/src/components/modules/common/data-table/data-table"; +import { columns } from "@/src/components/modules/batches/transaction-columns"; +import { + Card, + CardHeader, + CardTitle, + CardContent, + CardDescription, +} from "@/src/components/ui/card"; +import { useQuery } from "@tanstack/react-query"; +import { useRouter } from "next/router"; +import { getOptions } from "@/src/lib/constants"; +import TruncatedAddress from "@/src/components/modules/common/truncated-address"; + +export default function BatchTransactions() { + const router = useRouter(); + const { fullHash } = router.query; + const options = getOptions(router.query); + + const { data, isLoading, refetch } = useQuery({ + queryKey: ["batchTransactions", { fullHash, options }], + queryFn: () => fetchBatchTransactions(fullHash as string, options), + }); + + const { TransactionsData, Total } = data?.result || { + TransactionsData: [], + Total: 0, + }; + + return ( + + + + Transactions + +

    Overview of all transactions in this batch:

    + +
    +
    + + + +
    +
    + ); +} + +export async function getServerSideProps(context: any) { + return { + props: {}, + }; +} diff --git a/tools/tenscan/frontend/pages/batch/txs/[hash].tsx b/tools/tenscan/frontend/pages/batch/txs/[hash].tsx deleted file mode 100644 index 4de42bc959..0000000000 --- a/tools/tenscan/frontend/pages/batch/txs/[hash].tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React from "react"; -import { fetchBatchTransactions } from "../../../api/batches"; -import Layout from "../../../src/components/layouts/default-layout"; -import { DataTable } from "@repo/ui/components/common/data-table/data-table"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { columns } from "../../../src/components/modules/batches/transaction-columns"; -import { - Card, - CardHeader, - CardTitle, - CardContent, - CardDescription, -} from "@repo/ui/components/shared/card"; -import { useQuery } from "@tanstack/react-query"; -import { useRouter } from "next/router"; -import { getOptions } from "../../../src/lib/constants"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; - -export default function BatchTransactions() { - const router = useRouter(); - const { hash } = router.query; - const options = getOptions(router.query); - - const { data, isLoading, refetch } = useQuery({ - queryKey: ["batchTransactions", { hash, options }], - queryFn: () => fetchBatchTransactions(hash as string, options), - }); - - const { TransactionsData, Total } = data?.result || { - TransactionsData: [], - Total: 0, - }; - - return ( - - - - Transactions -
    - - - Overview of all transactions in this batch: - - - -
    -
    - - - -
    -
    - ); -} - -export async function getServerSideProps(context: any) { - return { - props: {}, - }; -} diff --git a/tools/tenscan/frontend/pages/batches/index.tsx b/tools/tenscan/frontend/pages/batches/index.tsx index 318460b4d6..2517daac17 100644 --- a/tools/tenscan/frontend/pages/batches/index.tsx +++ b/tools/tenscan/frontend/pages/batches/index.tsx @@ -1,13 +1,13 @@ import React from "react"; import { columns } from "@/src/components/modules/batches/columns"; -import { DataTable } from "@repo/ui/components/common/data-table/data-table"; +import { DataTable } from "@/src/components/modules/common/data-table/data-table"; import Layout from "@/src/components/layouts/default-layout"; import { Metadata } from "next"; import { useBatchesService } from "@/src/services/useBatchesService"; -import { getItem } from "@repo/ui/lib/utils"; +import { getItem } from "@/src/lib/utils"; +import { ItemPosition } from "@/src/types/interfaces"; import { siteMetadata } from "@/src/lib/siteMetadata"; import HeadSeo from "@/src/components/head-seo"; -import { ItemPosition } from "@repo/ui/lib/enums/ui"; export const metadata: Metadata = { title: "Batches", @@ -15,12 +15,22 @@ export const metadata: Metadata = { }; export default function Batches() { - const { batches, refetchBatches, isBatchesLoading } = useBatchesService(); + const { batches, refetchBatches, isBatchesLoading, setNoPolling } = + useBatchesService(); const { BatchesData, Total } = batches?.result || { BatchesData: [], Total: 0, }; + React.useEffect(() => { + setNoPolling(true); + + return () => { + setNoPolling(false); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const firstBatchHeight = Number(getItem(BatchesData, "height")); const lastBatchHeight = Number( getItem(BatchesData, "height", ItemPosition.LAST) diff --git a/tools/tenscan/frontend/pages/blocks/index.tsx b/tools/tenscan/frontend/pages/blocks/index.tsx index 4383266fe3..756add84b4 100644 --- a/tools/tenscan/frontend/pages/blocks/index.tsx +++ b/tools/tenscan/frontend/pages/blocks/index.tsx @@ -1,13 +1,13 @@ import React from "react"; import { columns } from "@/src/components/modules/blocks/columns"; -import { DataTable } from "@repo/ui/components/common/data-table/data-table"; +import { DataTable } from "@/src/components/modules/common/data-table/data-table"; import Layout from "@/src/components/layouts/default-layout"; import { Metadata } from "next"; import { useBlocksService } from "@/src/services/useBlocksService"; -import { getItem } from "@repo/ui/lib/utils"; +import { getItem } from "@/src/lib/utils"; +import { ItemPosition } from "@/src/types/interfaces"; import HeadSeo from "@/src/components/head-seo"; import { siteMetadata } from "@/src/lib/siteMetadata"; -import { ItemPosition } from "@repo/ui/lib/enums/ui"; export const metadata: Metadata = { title: "Blocks", @@ -15,12 +15,19 @@ export const metadata: Metadata = { }; export default function Blocks() { - const { blocks, refetchBlocks, isBlocksLoading } = useBlocksService(); + const { blocks, setNoPolling, refetchBlocks, isBlocksLoading } = + useBlocksService(); const { BlocksData, Total } = blocks?.result || { BlocksData: [], Total: 0, }; + React.useEffect(() => { + setNoPolling(true); + return () => setNoPolling(false); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const firstBlockNumber = Number(getItem(BlocksData, "blockHeader.number")); const lastBlockNumber = Number( getItem(BlocksData, "blockHeader.number", ItemPosition.LAST) diff --git a/tools/tenscan/frontend/pages/docs/[id].tsx b/tools/tenscan/frontend/pages/docs/[id].tsx index a1b4da5f6a..56ca02d6d0 100644 --- a/tools/tenscan/frontend/pages/docs/[id].tsx +++ b/tools/tenscan/frontend/pages/docs/[id].tsx @@ -1,11 +1,11 @@ import Layout from "@/src/components/layouts/default-layout"; +import Spinner from "@/src/components/ui/spinner"; import { siteMetadata } from "@/src/lib/siteMetadata"; import { useRouter } from "next/router"; import React from "react"; -import { showToast } from "@repo/ui/components/shared/use-toast"; -import { ToastType } from "@repo/ui/lib/enums/toast"; -import Custom404Error from "@repo/ui/components/common/404"; -import Spinner from "@repo/ui/components/shared/spinner"; +import Custom404Error from "../404"; +import { showToast } from "@/src/components/ui/use-toast"; +import { ToastType } from "@/src/types/interfaces"; type Document = { title: string; diff --git a/tools/tenscan/frontend/pages/personal/index.tsx b/tools/tenscan/frontend/pages/personal/index.tsx index d228f98e0d..28c4e74e70 100644 --- a/tools/tenscan/frontend/pages/personal/index.tsx +++ b/tools/tenscan/frontend/pages/personal/index.tsx @@ -1,13 +1,13 @@ import React from "react"; -import Layout from "../../src/components/layouts/default-layout"; +import Layout from "@/src/components/layouts/default-layout"; import { Metadata } from "next"; -import PersonalTransactions from "../../src/components/modules/personal"; -import useWalletStore from "@repo/ui/stores/wallet-store"; -import ConnectWalletButton from "@repo/ui/components/common/connect-wallet"; -import EmptyState from "@repo/ui/components/common/empty-state"; -import { ethereum } from "@repo/ui/lib/utils"; -import HeadSeo from "../../src/components/head-seo"; -import { siteMetadata } from "../../src/lib/siteMetadata"; +import PersonalTransactions from "@/src/components/modules/personal"; +import { useWalletConnection } from "@/src/components/providers/wallet-provider"; +import ConnectWalletButton from "@/src/components/modules/common/connect-wallet"; +import EmptyState from "@/src/components/modules/common/empty-state"; +import { ethereum } from "@/src/lib/utils"; +import HeadSeo from "@/src/components/head-seo"; +import { siteMetadata } from "@/src/lib/siteMetadata"; export const metadata: Metadata = { title: "Personal Transactions", @@ -15,7 +15,7 @@ export const metadata: Metadata = { }; export default function PersonalPage() { - const { walletConnected } = useWalletStore(); + const { walletConnected } = useWalletConnection(); return ( <> diff --git a/tools/tenscan/frontend/pages/rollup/[hash]/batches.tsx b/tools/tenscan/frontend/pages/rollup/[hash]/batches.tsx index e694ac4513..7df649aef2 100644 --- a/tools/tenscan/frontend/pages/rollup/[hash]/batches.tsx +++ b/tools/tenscan/frontend/pages/rollup/[hash]/batches.tsx @@ -1,9 +1,9 @@ import React from "react"; import { columns } from "@/src/components/modules/batches/columns"; -import { DataTable } from "@repo/ui/components/common/data-table/data-table"; +import { DataTable } from "@/src/components/modules/common/data-table/data-table"; import Layout from "@/src/components/layouts/default-layout"; import { Metadata } from "next"; -import { formatNumber } from "@repo/ui/lib/utils"; +import { formatNumber } from "@/src/lib/utils"; import { useRollupsService } from "@/src/services/useRollupsService"; export const metadata: Metadata = { diff --git a/tools/tenscan/frontend/pages/rollup/[hash]/index.tsx b/tools/tenscan/frontend/pages/rollup/[hash]/index.tsx index b121ef04c3..889f780409 100644 --- a/tools/tenscan/frontend/pages/rollup/[hash]/index.tsx +++ b/tools/tenscan/frontend/pages/rollup/[hash]/index.tsx @@ -1,16 +1,16 @@ import { fetchRollupByHash } from "@/api/rollups"; import Layout from "@/src/components/layouts/default-layout"; import { RollupDetailsComponent } from "@/src/components/modules/rollups/rollup-details"; -import EmptyState from "@repo/ui/components/common/empty-state"; -import LoadingState from "@repo/ui/components/common/loading-state"; -import { Button } from "@repo/ui/components/shared/button"; +import EmptyState from "@/src/components/modules/common/empty-state"; +import { Button } from "@/src/components/ui/button"; import { Card, CardHeader, CardTitle, CardContent, CardDescription, -} from "@repo/ui/components/shared/card"; +} from "@/src/components/ui/card"; +import { Skeleton } from "@/src/components/ui/skeleton"; import { useQuery } from "@tanstack/react-query"; import { useRouter } from "next/router"; @@ -28,7 +28,7 @@ export default function RollupDetails() { return ( {isLoading ? ( - + ) : rollupDetails ? ( diff --git a/tools/tenscan/frontend/pages/rollup/batch/sequence/[sequence].tsx b/tools/tenscan/frontend/pages/rollup/batch/sequence/[sequence].tsx index c551d16515..eb8b2716d8 100644 --- a/tools/tenscan/frontend/pages/rollup/batch/sequence/[sequence].tsx +++ b/tools/tenscan/frontend/pages/rollup/batch/sequence/[sequence].tsx @@ -1,18 +1,18 @@ import { fetchRollupByBatchSequence } from "@/api/rollups"; import Layout from "@/src/components/layouts/default-layout"; -import EmptyState from "@repo/ui/components/common/empty-state"; +import EmptyState from "@/src/components/modules/common/empty-state"; import { RollupDetailsComponent } from "@/src/components/modules/rollups/rollup-details"; -import { Button } from "@repo/ui/components/shared/button"; +import { Button } from "@/src/components/ui/button"; import { Card, CardHeader, CardTitle, CardContent, CardDescription, -} from "@repo/ui/components/shared/card"; +} from "@/src/components/ui/card"; +import { Skeleton } from "@/src/components/ui/skeleton"; import { useQuery } from "@tanstack/react-query"; import { useRouter } from "next/router"; -import LoadingState from "@repo/ui/components/common/loading-state"; export default function RollupBatchSequenceDetails() { const router = useRouter(); @@ -28,7 +28,7 @@ export default function RollupBatchSequenceDetails() { return ( {isLoading ? ( - + ) : rollupDetails ? ( diff --git a/tools/tenscan/frontend/pages/rollups/index.tsx b/tools/tenscan/frontend/pages/rollups/index.tsx index 7d8b6a19d1..f9932f73f8 100644 --- a/tools/tenscan/frontend/pages/rollups/index.tsx +++ b/tools/tenscan/frontend/pages/rollups/index.tsx @@ -1,13 +1,13 @@ import React from "react"; -import { DataTable } from "@repo/ui/components/common/data-table/data-table"; +import { DataTable } from "@/src/components/modules/common/data-table/data-table"; import Layout from "@/src/components/layouts/default-layout"; import { useRollupsService } from "@/src/services/useRollupsService"; import { Metadata } from "next"; import { columns } from "@/src/components/modules/rollups/columns"; -import { getItem } from "@repo/ui/lib/utils"; +import { getItem } from "@/src/lib/utils"; +import { ItemPosition } from "@/src/types/interfaces"; import HeadSeo from "@/src/components/head-seo"; import { siteMetadata } from "@/src/lib/siteMetadata"; -import { ItemPosition } from "@repo/ui/lib/enums/ui"; export const metadata: Metadata = { title: "Rollups", @@ -15,12 +15,22 @@ export const metadata: Metadata = { }; export default function Rollups() { - const { rollups, isRollupsLoading, refetchRollups } = useRollupsService(); + const { rollups, setNoPolling, isRollupsLoading, refetchRollups } = + useRollupsService(); const { RollupsData, Total } = rollups?.result || { RollupsData: [], Total: 0, }; + React.useEffect(() => { + setNoPolling(true); + + return () => { + setNoPolling(false); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const firstRollupID = Number(getItem(RollupsData, "ID")); const lastRollupID = Number(getItem(RollupsData, "ID", ItemPosition.LAST)); diff --git a/tools/tenscan/frontend/pages/transactions/index.tsx b/tools/tenscan/frontend/pages/transactions/index.tsx index 5225b70d3d..a94c0e45d4 100644 --- a/tools/tenscan/frontend/pages/transactions/index.tsx +++ b/tools/tenscan/frontend/pages/transactions/index.tsx @@ -1,13 +1,13 @@ import React from "react"; import { columns } from "@/src/components/modules/transactions/columns"; -import { DataTable } from "@repo/ui/components/common/data-table/data-table"; +import { DataTable } from "@/src/components/modules/common/data-table/data-table"; import Layout from "@/src/components/layouts/default-layout"; import { useTransactionsService } from "@/src/services/useTransactionsService"; import { Metadata } from "next"; -import { getItem } from "@repo/ui/lib/utils"; +import { getItem } from "@/src/lib/utils"; +import { ItemPosition } from "@/src/types/interfaces"; import HeadSeo from "@/src/components/head-seo"; import { siteMetadata } from "@/src/lib/siteMetadata"; -import { ItemPosition } from "@repo/ui/lib/enums/ui"; export const metadata: Metadata = { title: "Transactions", @@ -15,13 +15,26 @@ export const metadata: Metadata = { }; export default function Transactions() { - const { transactions, refetchTransactions, isTransactionsLoading } = - useTransactionsService(); + const { + transactions, + refetchTransactions, + setNoPolling, + isTransactionsLoading, + } = useTransactionsService(); const { TransactionsData, Total } = transactions?.result || { TransactionsData: [], Total: 0, }; + React.useEffect(() => { + setNoPolling(true); + + return () => { + setNoPolling(false); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const firstBatchHeight = getItem(TransactionsData, "BatchHeight"); const lastBatchHeight = getItem( TransactionsData, diff --git a/tools/tenscan/frontend/pages/tx/[hash].tsx b/tools/tenscan/frontend/pages/tx/[hash].tsx index dbd3077971..c47d0fb2ff 100644 --- a/tools/tenscan/frontend/pages/tx/[hash].tsx +++ b/tools/tenscan/frontend/pages/tx/[hash].tsx @@ -1,15 +1,15 @@ import { fetchTransactionByHash } from "@/api/transactions"; import Layout from "@/src/components/layouts/default-layout"; import { TransactionDetailsComponent } from "@/src/components/modules/transactions/transaction-details"; -import EmptyState from "@repo/ui/components/common/empty-state"; -import LoadingState from "@repo/ui/components/common/loading-state"; -import { Button } from "@repo/ui/components/shared/button"; +import EmptyState from "@/src/components/modules/common/empty-state"; +import { Button } from "@/src/components/ui/button"; import { Card, CardHeader, CardTitle, CardContent, -} from "@repo/ui/components/shared/card"; +} from "@/src/components/ui/card"; +import { Skeleton } from "@/src/components/ui/skeleton"; import { useQuery } from "@tanstack/react-query"; import { useRouter } from "next/router"; @@ -28,7 +28,14 @@ export default function TransactionDetails() { {isLoading ? ( - + <> + + + + + + + ) : transactionDetails ? ( <> diff --git a/tools/tenscan/frontend/pages/personal/tx/[hash].tsx b/tools/tenscan/frontend/pages/tx/personal/[hash].tsx similarity index 70% rename from tools/tenscan/frontend/pages/personal/tx/[hash].tsx rename to tools/tenscan/frontend/pages/tx/personal/[hash].tsx index 00dfdfbf60..65e0c9889c 100644 --- a/tools/tenscan/frontend/pages/personal/tx/[hash].tsx +++ b/tools/tenscan/frontend/pages/tx/personal/[hash].tsx @@ -1,25 +1,24 @@ -import React from "react"; -import Layout from "../../../src/components/layouts/default-layout"; -import EmptyState from "@repo/ui/components/common/empty-state"; -import { Button } from "@repo/ui/components/shared/button"; +import Layout from "@/src/components/layouts/default-layout"; +import EmptyState from "@/src/components/modules/common/empty-state"; +import { Button } from "@/src/components/ui/button"; import { Card, CardHeader, CardTitle, CardContent, -} from "@repo/ui/components/shared/card"; +} from "@/src/components/ui/card"; +import { Skeleton } from "@/src/components/ui/skeleton"; import { useQuery } from "@tanstack/react-query"; import { useRouter } from "next/router"; -import { fetchPersonalTxnByHash } from "../../../api/transactions"; -import { PersonalTxnDetailsComponent } from "../../../src/components/modules/personal/personal-txn-details"; -import { ethereum } from "@repo/ui/lib/utils"; -import useWalletStore from "@repo/ui/stores/wallet-store"; -import ConnectWalletButton from "@repo/ui/components/common/connect-wallet"; -import LoadingState from "@repo/ui/components/common/loading-state"; +import { fetchPersonalTxnByHash } from "@/api/transactions"; +import { useWalletConnection } from "@/src/components/providers/wallet-provider"; +import { PersonalTxnDetailsComponent } from "@/src/components/modules/personal/personal-txn-details"; +import ConnectWalletButton from "@/src/components/modules/common/connect-wallet"; +import { ethereum } from "@/src/lib/utils"; export default function TransactionDetails() { const router = useRouter(); - const { provider, walletConnected } = useWalletStore(); + const { provider, walletConnected } = useWalletConnection(); const { hash } = router.query; const { data: transactionDetails, isLoading } = useQuery({ @@ -32,7 +31,7 @@ export default function TransactionDetails() { {walletConnected ? ( isLoading ? ( - + ) : transactionDetails ? ( diff --git a/tools/tenscan/frontend/src/components/date-range-picker.tsx b/tools/tenscan/frontend/src/components/date-range-picker.tsx index 3c90d5c8a1..325a998b65 100644 --- a/tools/tenscan/frontend/src/components/date-range-picker.tsx +++ b/tools/tenscan/frontend/src/components/date-range-picker.tsx @@ -1,18 +1,18 @@ "use client"; import * as React from "react"; -import { CalendarIcon } from "@repo/ui/components/shared/react-icons"; +import { CalendarIcon } from "@radix-ui/react-icons"; import { addDays, format } from "date-fns"; import { DateRange } from "react-day-picker"; -import { cn } from "@repo/ui/lib/utils"; -import { Button } from "@repo/ui/components/shared/button"; -import { Calendar } from "@repo/ui/components/shared/calendar"; +import { cn } from "@/src/lib/utils"; +import { Button } from "@/src/components/ui/button"; +import { Calendar } from "@/src/components/ui/calendar"; import { Popover, PopoverContent, PopoverTrigger, -} from "@repo/ui/components/shared/popover"; +} from "@/src/components/ui/popover"; export function CalendarDateRangePicker({ className, diff --git a/tools/tenscan/frontend/src/components/head-seo.tsx b/tools/tenscan/frontend/src/components/head-seo.tsx index d6d588339f..3cafb9c345 100644 --- a/tools/tenscan/frontend/src/components/head-seo.tsx +++ b/tools/tenscan/frontend/src/components/head-seo.tsx @@ -1,6 +1,6 @@ import Head from "next/head"; +import { SeoProps } from "../types/interfaces"; import { siteMetadata } from "../lib/siteMetadata"; -import { SeoProps } from "@repo/ui/lib/interfaces/ui"; const HeadSeo = ({ title, diff --git a/tools/tenscan/frontend/src/components/health-indicator.tsx b/tools/tenscan/frontend/src/components/health-indicator.tsx index c522ac2a5d..c5c0f296dd 100644 --- a/tools/tenscan/frontend/src/components/health-indicator.tsx +++ b/tools/tenscan/frontend/src/components/health-indicator.tsx @@ -1,13 +1,13 @@ import React from "react"; -import { Badge, badgeVariants } from "@repo/ui/components/shared/badge"; +import { Badge, badgeVariants } from "./ui/badge"; import { useGeneralService } from "../services/useGeneralService"; -import { BarChart } from "@repo/ui/components/shared/react-icons"; +import { BarChart } from "lucide-react"; import { TooltipProvider, TooltipTrigger, TooltipContent, Tooltip, -} from "@repo/ui/components/shared/tooltip"; +} from "./ui/tooltip"; const HealthIndicator = () => { const [status, setStatus] = React.useState(false); diff --git a/tools/tenscan/frontend/src/components/layouts/footer.tsx b/tools/tenscan/frontend/src/components/layouts/footer.tsx index 465fdd6b91..319c42835c 100644 --- a/tools/tenscan/frontend/src/components/layouts/footer.tsx +++ b/tools/tenscan/frontend/src/components/layouts/footer.tsx @@ -1,11 +1,10 @@ import Link from "next/link"; -import { socialLinks } from "@repo/ui/lib/constants"; +import { socialLinks, version } from "../../lib/constants"; import { GitHubLogoIcon, TwitterLogoIcon, DiscordLogoIcon, -} from "@repo/ui/components/shared/react-icons"; -import { version } from "@/src/lib/constants"; +} from "@radix-ui/react-icons"; const SOCIAL_LINKS = [ { diff --git a/tools/tenscan/frontend/src/components/layouts/header.tsx b/tools/tenscan/frontend/src/components/layouts/header.tsx index b473e027c5..9ba8f94c00 100644 --- a/tools/tenscan/frontend/src/components/layouts/header.tsx +++ b/tools/tenscan/frontend/src/components/layouts/header.tsx @@ -1,12 +1,13 @@ -import { useState } from "react"; -import Link from "next/link"; -import Image from "next/image"; import { MainNav } from "../main-nav"; -import { ModeToggle } from "@repo/ui/components/shared/mode-toggle"; -import ConnectWalletButton from "@repo/ui/components/common/connect-wallet"; -import { HamburgerMenuIcon, X } from "@repo/ui/components/shared/react-icons"; -import { Button } from "@repo/ui/components/shared/button"; +import { ModeToggle } from "../mode-toggle"; +import ConnectWalletButton from "../modules/common/connect-wallet"; +import Link from "next/link"; +import { HamburgerMenuIcon } from "@radix-ui/react-icons"; +import { X } from "lucide-react"; +import { useState } from "react"; +import { Button } from "../ui/button"; import HealthIndicator from "../health-indicator"; +import Image from "next/image"; export default function Header() { return ( diff --git a/tools/tenscan/frontend/src/components/main-nav.tsx b/tools/tenscan/frontend/src/components/main-nav.tsx index 6f508f2e59..704af970cb 100644 --- a/tools/tenscan/frontend/src/components/main-nav.tsx +++ b/tools/tenscan/frontend/src/components/main-nav.tsx @@ -2,17 +2,17 @@ import React from "react"; import Link from "next/link"; import { useRouter } from "next/router"; -import { cn } from "@repo/ui/lib/utils"; -import { Button } from "@repo/ui/components/shared/button"; +import { cn } from "@/src/lib/utils"; +import { Button } from "./ui/button"; import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, -} from "@repo/ui/components/shared/dropdown-menu"; +} from "./ui/dropdown-menu"; -import { ChevronDownIcon } from "@repo/ui/components/shared/react-icons"; +import { ChevronDownIcon } from "@radix-ui/react-icons"; import { NavLink } from "@/src/types/interfaces"; import { NavLinks } from "../routes"; diff --git a/tools/tenscan/frontend/src/components/mode-toggle.tsx b/tools/tenscan/frontend/src/components/mode-toggle.tsx new file mode 100644 index 0000000000..7333cb883a --- /dev/null +++ b/tools/tenscan/frontend/src/components/mode-toggle.tsx @@ -0,0 +1,40 @@ +"use client"; + +import * as React from "react"; +import { Moon, Sun } from "lucide-react"; +import { useTheme } from "next-themes"; + +import { Button } from "@/src/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/src/components/ui/dropdown-menu"; + +export function ModeToggle() { + const { setTheme } = useTheme(); + + return ( + + + + + + setTheme("light")}> + Light + + setTheme("dark")}> + Dark + + setTheme("system")}> + System + + + + ); +} diff --git a/tools/tenscan/frontend/src/components/modules/batches/batch-hash-details.tsx b/tools/tenscan/frontend/src/components/modules/batches/batch-hash-details.tsx index 159d9b146d..f48a609f0b 100644 --- a/tools/tenscan/frontend/src/components/modules/batches/batch-hash-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/batches/batch-hash-details.tsx @@ -1,33 +1,22 @@ -import { useMemo, useState } from "react"; -import { Separator } from "@repo/ui/components/shared/separator"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import KeyValueItem, { - KeyValueList, -} from "@repo/ui/components/shared/key-value"; -import { - formatNumber, - formatTimeAgo, - formatTimestampToDate, -} from "@repo/ui/lib/utils"; -import { Badge } from "@repo/ui/components/shared/badge"; +import { Separator } from "@/src/components/ui/separator"; +import TruncatedAddress from "../common/truncated-address"; +import KeyValueItem, { KeyValueList } from "@/src/components/ui/key-value"; +import { formatNumber, formatTimeAgo } from "@/src/lib/utils"; +import { Badge } from "@/src/components/ui/badge"; +import { Batch, BatchDetails } from "@/src/types/interfaces/BatchInterfaces"; import Link from "next/link"; -import { - EyeClosedIcon, - EyeOpenIcon, -} from "@repo/ui/components/shared/react-icons"; -import { Button } from "@repo/ui/components/shared/button"; -import Copy from "@repo/ui/components/common/copy"; +import { EyeClosedIcon, EyeOpenIcon } from "@radix-ui/react-icons"; +import { Button } from "../../ui/button"; import { useRollupsService } from "@/src/services/useRollupsService"; import JSONPretty from "react-json-pretty"; +import { useState } from "react"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, -} from "@repo/ui/components/shared/tooltip"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; -import { BatchDetails } from "@/src/types/interfaces/BatchInterfaces"; +} from "../../ui/tooltip"; +import Copy from "../common/copy"; export function BatchHashDetailsComponent({ batchDetails, @@ -37,31 +26,6 @@ export function BatchHashDetailsComponent({ const { decryptedRollup, decryptEncryptedData } = useRollupsService(); const [showDecryptedData, setShowDecryptedData] = useState(false); - const transactionHashes = useMemo( - () => - batchDetails?.TxHashes.length > 0 ? ( -
      - {batchDetails.TxHashes.map((txHash, index) => ( -
    • - -
    • - ))} -
    - ) : ( - "-" - ), - [batchDetails?.TxHashes] - ); - - const handleDecryptToggle = () => { - decryptEncryptedData({ StrData: batchDetails?.EncryptedTxBlob }); - setShowDecryptedData(!showDecryptedData); - }; - return (
    @@ -69,9 +33,7 @@ export function BatchHashDetailsComponent({ label="Batch Height" value={ {"#" + Number(batchDetails?.Header?.number)} @@ -80,75 +42,47 @@ export function BatchHashDetailsComponent({ /> - } + value={} /> + } /> - } + value={} /> } /> + } /> - {formatTimeAgo(batchDetails?.Header?.timestamp) + - " - " + - formatTimestampToDate(batchDetails?.Header?.timestamp)} + + {formatTimeAgo(batchDetails?.Header?.timestamp)} } /> - } + value={} /> - {formatNumber(batchDetails?.Header?.gasLimit)} - - } + value={formatNumber(batchDetails?.Header?.gasLimit)} /> - {formatNumber(batchDetails?.Header?.baseFeePerGas)} - - } + value={batchDetails?.Header?.baseFeePerGas || "-"} /> } /> @@ -177,54 +106,73 @@ export function BatchHashDetailsComponent({ /> - } + value={} /> - + + + + + {batchDetails?.TxHashes?.map((txHash, index) => ( +
  • + +
  • + ))} + + ) : ( + "-" + ) + } isLastItem />
    - -
    - + {" "} - - {showDecryptedData && decryptedRollup && ( + {showDecryptedData && decryptedRollup ? ( @@ -235,14 +183,14 @@ export function BatchHashDetailsComponent({ - )} + ) : null}
    - {showDecryptedData && decryptedRollup && ( + {decryptedRollup && showDecryptedData ? ( <> - )} + ) : null} } isLastItem diff --git a/tools/tenscan/frontend/src/components/modules/batches/batch-height-details.tsx b/tools/tenscan/frontend/src/components/modules/batches/batch-height-details.tsx index 4c58f4654f..c19a2d07c5 100644 --- a/tools/tenscan/frontend/src/components/modules/batches/batch-height-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/batches/batch-height-details.tsx @@ -1,32 +1,21 @@ -import { Separator } from "@repo/ui/components/shared/separator"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import KeyValueItem, { - KeyValueList, -} from "@repo/ui/components/shared/key-value"; -import { - formatNumber, - formatTimeAgo, - formatTimestampToDate, -} from "@repo/ui/lib/utils"; -import { Badge } from "@repo/ui/components/shared/badge"; -import { Batch } from "@/src/types/interfaces/BatchInterfaces"; +import { Separator } from "@/src/components/ui/separator"; +import TruncatedAddress from "../common/truncated-address"; +import KeyValueItem, { KeyValueList } from "@/src/components/ui/key-value"; +import { formatNumber, formatTimeAgo } from "@/src/lib/utils"; +import { Badge } from "@/src/components/ui/badge"; +import { Batch, BatchDetails } from "@/src/types/interfaces/BatchInterfaces"; import Link from "next/link"; -import { - EyeClosedIcon, - EyeOpenIcon, -} from "@repo/ui/components/shared/react-icons"; -import { Button } from "@repo/ui/components/shared/button"; +import { EyeClosedIcon, EyeOpenIcon } from "@radix-ui/react-icons"; +import { Button } from "../../ui/button"; import { useRollupsService } from "@/src/services/useRollupsService"; import JSONPretty from "react-json-pretty"; -import React, { useState } from "react"; +import { useState } from "react"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, -} from "@repo/ui/components/shared/tooltip"; -import { pageLinks } from "@/src/routes"; -import { pathToUrl } from "@/src/routes/router"; +} from "../../ui/tooltip"; export function BatchHeightDetailsComponent({ batchDetails, @@ -52,67 +41,45 @@ export function BatchHeightDetailsComponent({ value={ } /> + } /> - } + value={} /> } /> + } /> - {formatTimeAgo(batchDetails?.header?.timestamp) + - " - " + - formatTimestampToDate(batchDetails?.header?.timestamp)} + {formatTimeAgo(batchDetails?.header?.timestamp)} } /> - } + value={} /> } /> @@ -149,12 +115,7 @@ export function BatchHeightDetailsComponent({ /> - } + value={} /> 0 ? ( - - {batchDetails?.txCount}{" "} - - View - - - ) : ( - batchDetails?.txCount || "-" - ) + + {batchDetails?.txCount || "-"} + } isLastItem /> diff --git a/tools/tenscan/frontend/src/components/modules/batches/columns.tsx b/tools/tenscan/frontend/src/components/modules/batches/columns.tsx index 721d15b5b2..c53138b099 100644 --- a/tools/tenscan/frontend/src/components/modules/batches/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/batches/columns.tsx @@ -2,14 +2,12 @@ import { ColumnDef } from "@tanstack/react-table"; -import { DataTableColumnHeader } from "@repo/ui/components/common/data-table/data-table-column-header"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { formatNumber, formatTimeAgo } from "@repo/ui/lib/utils"; +import { DataTableColumnHeader } from "../common/data-table/data-table-column-header"; +import TruncatedAddress from "../common/truncated-address"; +import { formatNumber, formatTimeAgo } from "@/src/lib/utils"; import { Batch } from "@/src/types/interfaces/BatchInterfaces"; import Link from "next/link"; -import { Badge } from "@repo/ui/components/shared/badge"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; +import { Badge } from "../../ui/badge"; export const columns: ColumnDef[] = [ { @@ -21,9 +19,7 @@ export const columns: ColumnDef[] = [ return (
    @@ -102,9 +98,7 @@ export const columns: ColumnDef[] = [ return ( ); }, @@ -130,9 +124,7 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { return ( {row.original.sequence} @@ -148,17 +140,13 @@ export const columns: ColumnDef[] = [ ), cell: ({ row }) => { - return row.original.txCount > 0 ? ( + return ( {row.original.txCount} - ) : ( - {row.original.txCount} ); }, enableSorting: false, diff --git a/tools/tenscan/frontend/src/components/modules/batches/constants.tsx b/tools/tenscan/frontend/src/components/modules/batches/constants.tsx index 6f740be779..395dc4771b 100644 --- a/tools/tenscan/frontend/src/components/modules/batches/constants.tsx +++ b/tools/tenscan/frontend/src/components/modules/batches/constants.tsx @@ -3,7 +3,7 @@ import { ArrowRightIcon, ArrowUpIcon, CheckCircledIcon, -} from "@repo/ui/components/shared/react-icons"; +} from "@radix-ui/react-icons"; export const labels = [ { diff --git a/tools/tenscan/frontend/src/components/modules/batches/transaction-columns.tsx b/tools/tenscan/frontend/src/components/modules/batches/transaction-columns.tsx index 5ce0aa849b..4e1e97ff75 100644 --- a/tools/tenscan/frontend/src/components/modules/batches/transaction-columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/batches/transaction-columns.tsx @@ -1,15 +1,15 @@ "use client"; import { ColumnDef } from "@tanstack/react-table"; -import { Badge } from "@repo/ui/components/shared/badge"; +import { Badge } from "@/src/components/ui/badge"; + import { statuses } from "../transactions/constants"; -import { DataTableColumnHeader } from "@repo/ui/components/common/data-table/data-table-column-header"; +import { DataTableColumnHeader } from "../common/data-table/data-table-column-header"; import { Transaction } from "@/src/types/interfaces/TransactionInterfaces"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { formatTimeAgo } from "@repo/ui/lib/utils"; +import TruncatedAddress from "../common/truncated-address"; +import { formatNumber, formatTimeAgo } from "@/src/lib/utils"; import Link from "next/link"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; +import { EyeOpenIcon } from "@radix-ui/react-icons"; export const columns: ColumnDef[] = [ { @@ -39,9 +39,7 @@ export const columns: ColumnDef[] = [ return ( ); }, diff --git a/tools/tenscan/frontend/src/components/modules/blocks/columns.tsx b/tools/tenscan/frontend/src/components/modules/blocks/columns.tsx index b7b04e657a..ee189d114b 100644 --- a/tools/tenscan/frontend/src/components/modules/blocks/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/blocks/columns.tsx @@ -2,15 +2,14 @@ import { ColumnDef } from "@tanstack/react-table"; -import { DataTableColumnHeader } from "@repo/ui/components/common/data-table/data-table-column-header"; +import { DataTableColumnHeader } from "../common/data-table/data-table-column-header"; import { Block, BlockHeader } from "@/src/types/interfaces/BlockInterfaces"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { formatNumber, formatTimeAgo } from "@repo/ui/lib/utils"; -import { Badge } from "@repo/ui/components/shared/badge"; -import ExternalLink from "@repo/ui/components/shared/external-link"; -import { externalPageLinks, pageLinks } from "@/src/routes"; -import { EyeOpenIcon } from "@repo/ui/components/shared/react-icons"; -import { pathToUrl } from "@/src/routes/router"; +import TruncatedAddress from "../common/truncated-address"; +import { formatNumber, formatTimeAgo } from "@/src/lib/utils"; +import { Badge } from "../../ui/badge"; +import ExternalLink from "../../ui/external-link"; +import { externalLinks } from "@/src/routes"; +import { EyeOpenIcon } from "@radix-ui/react-icons"; export const columns: ColumnDef[] = [ { @@ -63,9 +62,7 @@ export const columns: ColumnDef[] = [ ) : ( ); }, @@ -155,9 +152,7 @@ export const columns: ColumnDef[] = [ const blockHeader = row.original.blockHeader as BlockHeader; return ( diff --git a/tools/tenscan/frontend/src/components/modules/blocks/constants.tsx b/tools/tenscan/frontend/src/components/modules/blocks/constants.tsx index b26313a56d..eca2d7c2b5 100644 --- a/tools/tenscan/frontend/src/components/modules/blocks/constants.tsx +++ b/tools/tenscan/frontend/src/components/modules/blocks/constants.tsx @@ -2,7 +2,7 @@ import { ArrowDownIcon, ArrowRightIcon, ArrowUpIcon, -} from "@repo/ui/components/shared/react-icons"; +} from "@radix-ui/react-icons"; export const priorities = [ { diff --git a/tools/tenscan/frontend/src/components/modules/common/connect-wallet.tsx b/tools/tenscan/frontend/src/components/modules/common/connect-wallet.tsx new file mode 100644 index 0000000000..0bdba6765e --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/connect-wallet.tsx @@ -0,0 +1,43 @@ +import { useWalletConnection } from "@/src/components/providers/wallet-provider"; +import { Button } from "@/src/components/ui/button"; +import { Link2Icon, LinkBreak2Icon } from "@radix-ui/react-icons"; +import React from "react"; +import TruncatedAddress from "./truncated-address"; +import { downloadMetaMask, ethereum } from "@/src/lib/utils"; +const ConnectWalletButton = ({ text }: { text?: string }) => { + const { walletConnected, walletAddress, connectWallet, disconnectWallet } = + useWalletConnection(); + + return ( + + ); +}; + +export default ConnectWalletButton; diff --git a/tools/tenscan/frontend/src/components/modules/common/copy.tsx b/tools/tenscan/frontend/src/components/modules/common/copy.tsx new file mode 100644 index 0000000000..d24114ed0d --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/copy.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import { CopyIcon, CheckIcon } from "@radix-ui/react-icons"; +import { useCopy } from "@/src/hooks/useCopy"; +import { Button } from "../../ui/button"; + +const Copy = ({ value }: { value: string | number }) => { + const { copyToClipboard, copied } = useCopy(); + return ( + + ); +}; + +export default Copy; diff --git a/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-column-header.tsx b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-column-header.tsx new file mode 100644 index 0000000000..07fbb0cc3a --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-column-header.tsx @@ -0,0 +1,71 @@ +import { + ArrowDownIcon, + ArrowUpIcon, + CaretSortIcon, + EyeNoneIcon, +} from "@radix-ui/react-icons"; +import { Column } from "@tanstack/react-table"; + +import { cn } from "@/src/lib/utils"; +import { Button } from "@/src/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/src/components/ui/dropdown-menu"; + +interface DataTableColumnHeaderProps + extends React.HTMLAttributes { + column: Column; + title: string; +} + +export function DataTableColumnHeader({ + column, + title, + className, +}: DataTableColumnHeaderProps) { + if (!column.getCanSort()) { + return
    {title}
    ; + } + + return ( +
    + + + + + + column.toggleSorting(false)}> + + Asc + + column.toggleSorting(true)}> + + Desc + + + column.toggleVisibility(false)}> + + Hide + + + +
    + ); +} diff --git a/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-faceted-filter.tsx b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-faceted-filter.tsx new file mode 100644 index 0000000000..641973c663 --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-faceted-filter.tsx @@ -0,0 +1,147 @@ +import * as React from "react"; +import { CheckIcon, PlusCircledIcon } from "@radix-ui/react-icons"; +import { Column } from "@tanstack/react-table"; + +import { cn } from "@/src/lib/utils"; +import { Badge } from "@/src/components/ui/badge"; +import { Button } from "@/src/components/ui/button"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, +} from "@/src/components/ui/command"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/src/components/ui/popover"; +import { Separator } from "@/src/components/ui/separator"; + +interface DataTableFacetedFilterProps { + column?: Column; + title?: string; + options: { + label: string; + value: string; + icon?: React.ComponentType<{ className?: string }>; + }[]; +} + +export function DataTableFacetedFilter({ + column, + title, + options, +}: DataTableFacetedFilterProps) { + const facets = column?.getFacetedUniqueValues(); + const selectedValues = new Set(column?.getFilterValue() as string[]); + + return ( + + + + + + + + + No results found. + + {options.map((option) => { + const isSelected = selectedValues.has(option.value); + return ( + { + if (isSelected) { + selectedValues.delete(option.value); + } else { + selectedValues.add(option.value); + } + const filterValues = Array.from(selectedValues); + column?.setFilterValue( + filterValues.length ? filterValues : undefined + ); + }} + > +
    + +
    + {option.icon && ( + + )} + {option.label} + {facets?.get(option.value) && ( + + {facets.get(option.value)} + + )} +
    + ); + })} +
    + {selectedValues.size > 0 && ( + <> + + + column?.setFilterValue(undefined)} + className="justify-center text-center" + > + Clear filters + + + + )} +
    +
    +
    +
    + ); +} diff --git a/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-pagination.tsx b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-pagination.tsx new file mode 100644 index 0000000000..0a61d0f786 --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-pagination.tsx @@ -0,0 +1,144 @@ +import { + ChevronLeftIcon, + ChevronRightIcon, + DoubleArrowLeftIcon, +} from "@radix-ui/react-icons"; +import { PaginationState, Table } from "@tanstack/react-table"; +import { Button } from "@/src/components/ui/button"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/src/components/ui/select"; +import { Input } from "@/src/components/ui/input"; +import { useState } from "react"; + +interface DataTablePaginationProps { + table: Table; + refetch?: () => void; + setPagination: (pagination: PaginationState) => void; +} + +export function DataTablePagination({ + table, + refetch, + setPagination, +}: DataTablePaginationProps) { + const [page, setPage] = useState(table.getState().pagination.pageIndex); + + const handlePageChange = (e: React.ChangeEvent) => { + setPage(Number(e.target.value)); + }; + + const handleKey = (e: React.KeyboardEvent) => { + if ( + e.key === "Enter" && + page > 0 && + page !== table.getState().pagination.pageIndex + ) { + table.setPageIndex(page); + refetch?.(); + } + }; + + return ( +
    +
    + Showing {table?.getFilteredRowModel()?.rows?.length} row(s) +
    +
    +
    +

    Rows per page

    + +
    +
    + Page + e.target.select()} + onBlur={() => setPage(table.getState().pagination.pageIndex)} + /> + {/* uncomment the following line when total count feature is implemented */} + {/* of {formatNumber(table.getPageCount())} */} +
    +
    + + + + {/* uncomment the following line when total count feature is implemented */} + {/* */} +
    +
    +
    + ); +} diff --git a/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-row-actions.tsx b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-row-actions.tsx new file mode 100644 index 0000000000..0f8c652451 --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-row-actions.tsx @@ -0,0 +1,65 @@ +"use client"; + +import { DotsHorizontalIcon } from "@radix-ui/react-icons"; +import { Row } from "@tanstack/react-table"; +import { Button } from "@/src/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from "@/src/components/ui/dropdown-menu"; + +interface DataTableRowActionsProps { + row: Row; + labels: { label: string; value: string }[] | null; +} + +export function DataTableRowActions({ + row, + labels, +}: DataTableRowActionsProps) { + return ( + + + + + + View + {labels === null ? null : ( + <> + + + Labels + + + {labels?.map((label) => ( + + {label.label} + + ))} + + + + + )} + + + + ); +} diff --git a/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-toolbar.tsx b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-toolbar.tsx new file mode 100644 index 0000000000..93bee611c0 --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-toolbar.tsx @@ -0,0 +1,68 @@ +"use client"; + +import { Cross2Icon, ReloadIcon } from "@radix-ui/react-icons"; +import { Table } from "@tanstack/react-table"; + +import { Button } from "@/src/components/ui/button"; +import { Input } from "@/src/components/ui/input"; +import { DataTableViewOptions } from "./data-table-view-options"; + +import { DataTableFacetedFilter } from "./data-table-faceted-filter"; + +interface DataTableToolbarProps { + table: Table; + refetch?: () => void; + toolbar?: { + column: string; + title: string; + options: { label: string; value: string }[]; + }[]; +} +export function DataTableToolbar({ + table, + toolbar, + refetch, +}: DataTableToolbarProps) { + const isFiltered = table.getState().columnFilters.length > 0; + + return ( +
    +
    + {toolbar?.map( + (item, index) => + table.getColumn(item.column) && ( + + ) + )} + {isFiltered && ( + + )} +
    +
    + {refetch && ( + + )} + +
    +
    + ); +} diff --git a/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-view-options.tsx b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-view-options.tsx new file mode 100644 index 0000000000..b8975ff5cb --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table-view-options.tsx @@ -0,0 +1,59 @@ +"use client"; + +import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu"; +import { MixerHorizontalIcon } from "@radix-ui/react-icons"; +import { Table } from "@tanstack/react-table"; + +import { Button } from "@/src/components/ui/button"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuSeparator, +} from "@/src/components/ui/dropdown-menu"; + +interface DataTableViewOptionsProps { + table: Table; +} + +export function DataTableViewOptions({ + table, +}: DataTableViewOptionsProps) { + return ( + + + + + + Toggle columns + + {table + .getAllColumns() + .filter( + (column) => + typeof column.accessorFn !== "undefined" && column.getCanHide() + ) + .map((column) => { + return ( + column.toggleVisibility(!!value)} + > + {column.id} + + ); + })} + + + ); +} diff --git a/tools/tenscan/frontend/src/components/modules/common/data-table/data-table.tsx b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table.tsx new file mode 100644 index 0000000000..982835d6d4 --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/data-table/data-table.tsx @@ -0,0 +1,211 @@ +"use client"; + +import * as React from "react"; +import { + ColumnDef, + ColumnFiltersState, + OnChangeFn, + PaginationState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFacetedRowModel, + getFacetedUniqueValues, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/src/components/ui/table"; +import { DataTablePagination } from "./data-table-pagination"; +import { DataTableToolbar } from "./data-table-toolbar"; +import { useRouter } from "next/router"; +import { Skeleton } from "@/src/components/ui/skeleton"; +import { Button } from "@/src/components/ui/button"; + +interface DataTableProps { + columns: ColumnDef[]; + data: TData[]; + toolbar?: { + column: string; + title: string; + options: { label: string; value: string }[]; + }[]; + updateQueryParams?: (query: any) => void; + refetch?: () => void; + total: number; + isLoading?: boolean; + noPagination?: boolean; + noResultsText?: string; + noResultsMessage?: string; +} + +export function DataTable({ + columns, + data, + toolbar, + refetch, + total, + isLoading, + noPagination, + noResultsText, + noResultsMessage, +}: DataTableProps) { + const { query, push, pathname } = useRouter(); + const [rowSelection, setRowSelection] = React.useState({}); + const [columnVisibility, setColumnVisibility] = + React.useState({}); + const [columnFilters, setColumnFilters] = React.useState( + [] + ); + const [sorting, setSorting] = React.useState([]); + + const pagination = React.useMemo(() => { + return { + pageIndex: Number(query.page) || 1, + pageSize: Number(query.size) || 20, + }; + }, [query.page, query.size]); + + const setPagination: OnChangeFn = (func) => { + const { pageIndex, pageSize } = + typeof func === "function" ? func(pagination) : func; + const newPageIndex = pagination.pageSize !== pageSize ? 1 : pageIndex; + const params = { + ...query, + page: newPageIndex > 0 ? newPageIndex : 1, + size: pageSize <= 100 ? pageSize : 100, + }; + push({ pathname, query: params }); + }; + + const table = useReactTable({ + data, + columns, + state: { + sorting, + columnVisibility, + rowSelection, + columnFilters, + pagination, + }, + onPaginationChange: setPagination, + manualPagination: true, + // pageCount: Math.ceil(total / pagination.pageSize), + enableRowSelection: true, + onRowSelectionChange: setRowSelection, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + onColumnVisibilityChange: setColumnVisibility, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFacetedRowModel: getFacetedRowModel(), + getFacetedUniqueValues: getFacetedUniqueValues(), + }); + + return ( +
    + {data && ( + + )} +
    + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ); + })} + + ))} + + + {isLoading ? ( + <> + + + + + + + ) : data && table?.getRowModel()?.rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + {pagination.pageIndex > 1 ? ( +

    + No {noResultsText || "results"} found for the selected + filters. + +

    + ) : ( +

    + {noResultsMessage || + `No ${noResultsText || "results"} found.`} +

    + )} +
    +
    + )} +
    +
    +
    + {data && !isLoading && !noPagination && ( + + )} +
    + ); +} diff --git a/tools/tenscan/frontend/src/components/modules/common/data-table/skeleton-loader.tsx b/tools/tenscan/frontend/src/components/modules/common/data-table/skeleton-loader.tsx new file mode 100644 index 0000000000..89c5627fda --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/data-table/skeleton-loader.tsx @@ -0,0 +1,23 @@ +import { Skeleton } from "@/src/components/ui/skeleton"; +import { TableHeader, TableRow, TableBody } from "@/src/components/ui/table"; +import { Table } from "lucide-react"; +import React from "react"; + +const DataTableSkeleton = ({ columns }: { columns: number }) => { + const renderSkeletonColumns = () => { + return Array.from({ length: columns }).map((_, index) => ( + + )); + }; + + return ( + + + {renderSkeletonColumns()} + + {renderSkeletonColumns()} +
    + ); +}; + +export default DataTableSkeleton; diff --git a/tools/tenscan/frontend/src/components/modules/common/empty-state.tsx b/tools/tenscan/frontend/src/components/modules/common/empty-state.tsx new file mode 100644 index 0000000000..0372c45bd1 --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/empty-state.tsx @@ -0,0 +1,54 @@ +import { cn } from "@/src/lib/utils"; +import Image from "next/image"; +import React from "react"; + +const EmptyState = ({ + title, + description, + icon, + imageSrc, + imageAlt, + action, + className, +}: { + title?: string; + description?: string; + icon?: React.ReactNode; + imageSrc?: string; + imageAlt?: string; + action?: React.ReactNode; + className?: string; +}) => { + return ( +
    +
    + {icon &&
    {icon}
    } + {imageSrc && ( + {imageAlt + )} + {title && ( +

    + {title} +

    + )} + {description && ( +

    {description}

    + )} + {action &&
    {action}
    } +
    +
    + ); +}; + +export default EmptyState; diff --git a/tools/tenscan/frontend/src/components/modules/common/network-status.tsx b/tools/tenscan/frontend/src/components/modules/common/network-status.tsx new file mode 100644 index 0000000000..6f9be08af4 --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/network-status.tsx @@ -0,0 +1,40 @@ +import { cn } from "@/src/lib/utils"; +import React from "react"; + +const MessageContent = ( +

    + You seem to be offline +
    Please check your internet connection. +

    +); + +export const NetworkStatus = ({ message = MessageContent }) => { + const [isOnline, setIsOnline] = React.useState(true); + + React.useEffect(() => { + const setOnlineStatus = () => { + setIsOnline(navigator.onLine); + }; + + window.addEventListener("online", setOnlineStatus); + window.addEventListener("offline", setOnlineStatus); + + return () => { + window.removeEventListener("online", setOnlineStatus); + window.removeEventListener("offline", setOnlineStatus); + }; + }, []); + + return ( +
    +
    + {message} +
    +
    + ); +}; diff --git a/tools/tenscan/frontend/src/components/modules/common/truncated-address.tsx b/tools/tenscan/frontend/src/components/modules/common/truncated-address.tsx new file mode 100644 index 0000000000..789a21e8fd --- /dev/null +++ b/tools/tenscan/frontend/src/components/modules/common/truncated-address.tsx @@ -0,0 +1,72 @@ +import React from "react"; + +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/src/components/ui/tooltip"; + +import Copy from "./copy"; +import Link from "next/link"; + +const TruncatedAddress = ({ + address, + prefixLength, + suffixLength, + showCopy = true, + link, +}: { + address: string; + prefixLength?: number; + suffixLength?: number; + showCopy?: boolean; + link?: + | string + | { + pathname: string; + query: { [key: string]: string | number }; + }; +}) => { + const truncatedAddress = `${address?.substring( + 0, + prefixLength || 6 + )}...${address?.substring(address.length - (suffixLength || 4))}`; + + return ( + <> + {address ? ( +
    + {link ? ( + + + + + {truncatedAddress} + + + +

    {address}

    +
    +
    +
    + ) : ( + + + {truncatedAddress} + +

    {address}

    +
    +
    +
    + )} + {showCopy && } +
    + ) : ( +
    N/A
    + )} + + ); +}; + +export default TruncatedAddress; diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/analytics-card.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/analytics-card.tsx index 3f14c5247b..41c6b6448e 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/analytics-card.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/analytics-card.tsx @@ -1,11 +1,11 @@ -import { DashboardAnalyticsData } from "@/src/types/interfaces"; import { Card, CardHeader, CardTitle, CardContent, -} from "@repo/ui/components/shared/card"; -import { Skeleton } from "@repo/ui/components/shared/skeleton"; +} from "@/src/components/ui/card"; +import { Skeleton } from "@/src/components/ui/skeleton"; +import { DashboardAnalyticsData } from "@/src/types/interfaces"; import React from "react"; export default function AnalyticsCard({ diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx index 07ee091b50..18124148f6 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/index.tsx @@ -4,33 +4,31 @@ import { CardTitle, CardContent, Card, -} from "@repo/ui/components/shared/card"; +} from "@/src/components/ui/card"; import { LayersIcon, FileTextIcon, ReaderIcon, CubeIcon, RocketIcon, - BlocksIcon, -} from "@repo/ui/components/shared/react-icons"; +} from "@radix-ui/react-icons"; import { RecentBatches } from "./recent-batches"; import { RecentTransactions } from "./recent-transactions"; -import { Button } from "@repo/ui/components/shared/button"; +import { Button } from "@/src/components/ui/button"; import { useTransactionsService } from "@/src/services/useTransactionsService"; import { useBatchesService } from "@/src/services/useBatchesService"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; +import TruncatedAddress from "../common/truncated-address"; import { useContractsService } from "@/src/services/useContractsService"; -import { Skeleton } from "@repo/ui/components/shared/skeleton"; +import { Skeleton } from "@/src/components/ui/skeleton"; import AnalyticsCard from "./analytics-card"; import Link from "next/link"; -import { cn, formatNumber } from "@repo/ui/lib/utils"; -import { Badge } from "@repo/ui/components/shared/badge"; - +import { cn, formatNumber } from "@/src/lib/utils"; +import { Badge } from "../../ui/badge"; +import { BlocksIcon } from "lucide-react"; import { useRollupsService } from "@/src/services/useRollupsService"; import { RecentRollups } from "./recent-rollups"; import { DashboardAnalyticsData } from "@/src/types/interfaces"; -import { pageLinks } from "@/src/routes"; interface RecentData { title: string; @@ -47,29 +45,10 @@ export default function Dashboard() { transactions, transactionCount, isTransactionCountLoading, - setNoPolling: setNoPollingTransactions, } = useTransactionsService(); const { contractCount, isContractCountLoading } = useContractsService(); - const { - batches, - latestBatch, - isLatestBatchLoading, - setNoPolling: setNoPollingBatches, - } = useBatchesService(); - const { rollups, setNoPolling: setNoPollingRollups } = useRollupsService(); - - React.useEffect(() => { - setNoPollingTransactions(false); - setNoPollingBatches(false); - setNoPollingRollups(false); - - return () => { - setNoPollingTransactions(true); - setNoPollingBatches(true); - setNoPollingRollups(true); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const { batches, latestBatch, isLatestBatchLoading } = useBatchesService(); + const { rollups } = useRollupsService(); const DASHBOARD_DATA = [ { @@ -138,21 +117,21 @@ export default function Dashboard() { title: "Recent Rollups", data: rollups, component: , - goTo: pageLinks.rollups, + goTo: "/rollups", className: "col-span-1 md:col-span-2 lg:col-span-3", }, { title: "Recent Batches", data: batches, component: , - goTo: pageLinks.batches, + goTo: "/batches", className: "col-span-1 md:col-span-2 lg:col-span-3", }, { title: "Recent Transactions", data: transactions, component: , - goTo: pageLinks.transactions, + goTo: "/transactions", className: "col-span-1 md:col-span-2 lg:col-span-3", }, ]; diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/recent-batches.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/recent-batches.tsx index 510ba09cae..cf85c04a6b 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/recent-batches.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/recent-batches.tsx @@ -1,10 +1,8 @@ -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { formatTimeAgo } from "@repo/ui/lib/utils"; +import TruncatedAddress from "../common/truncated-address"; +import { formatTimeAgo } from "@/src/lib/utils"; import { Batch } from "@/src/types/interfaces/BatchInterfaces"; -import { Avatar, AvatarFallback } from "@repo/ui/components/shared/avatar"; +import { Avatar, AvatarFallback } from "@/src/components/ui/avatar"; import Link from "next/link"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; export function RecentBatches({ batches }: { batches: any }) { return ( @@ -17,9 +15,7 @@ export function RecentBatches({ batches }: { batches: any }) {

    #{Number(batch?.height)} @@ -32,9 +28,7 @@ export function RecentBatches({ batches }: { batches: any }) {

    diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/recent-rollups.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/recent-rollups.tsx index 1c1dd93dec..30353562a7 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/recent-rollups.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/recent-rollups.tsx @@ -1,9 +1,11 @@ -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { formatTimeAgo } from "@repo/ui/lib/utils"; -import { Avatar, AvatarFallback } from "@repo/ui/components/shared/avatar"; -import { Rollup } from "@/src/types/interfaces/RollupInterfaces"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; +import TruncatedAddress from "../common/truncated-address"; +import { formatTimeAgo } from "@/src/lib/utils"; +import { Avatar, AvatarFallback } from "@/src/components/ui/avatar"; +import { + Rollup, + RollupsResponse, +} from "@/src/types/interfaces/RollupInterfaces"; +import Link from "next/link"; export function RecentRollups({ rollups }: { rollups: any }) { return ( @@ -24,7 +26,7 @@ export function RecentRollups({ rollups }: { rollups: any }) {
    diff --git a/tools/tenscan/frontend/src/components/modules/dashboard/recent-transactions.tsx b/tools/tenscan/frontend/src/components/modules/dashboard/recent-transactions.tsx index e94fc1b00d..79698a5788 100644 --- a/tools/tenscan/frontend/src/components/modules/dashboard/recent-transactions.tsx +++ b/tools/tenscan/frontend/src/components/modules/dashboard/recent-transactions.tsx @@ -1,11 +1,9 @@ -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { Avatar, AvatarFallback } from "@repo/ui/components/shared/avatar"; +import TruncatedAddress from "../common/truncated-address"; +import { Avatar, AvatarFallback } from "@/src/components/ui/avatar"; import { Transaction } from "@/src/types/interfaces/TransactionInterfaces"; -import { Badge } from "@repo/ui/components/shared/badge"; -import { formatTimeAgo } from "@repo/ui/lib/utils"; +import { Badge } from "../../ui/badge"; +import { formatTimeAgo } from "@/src/lib/utils"; import Link from "next/link"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; export function RecentTransactions({ transactions }: { transactions: any }) { return ( @@ -20,9 +18,7 @@ export function RecentTransactions({ transactions }: { transactions: any }) {

    Batch #{Number(transaction?.BatchHeight)} @@ -35,9 +31,7 @@ export function RecentTransactions({ transactions }: { transactions: any }) {

    diff --git a/tools/tenscan/frontend/src/components/modules/personal/columns.tsx b/tools/tenscan/frontend/src/components/modules/personal/columns.tsx index 9dda107e44..3c1faa6ac9 100644 --- a/tools/tenscan/frontend/src/components/modules/personal/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/personal/columns.tsx @@ -1,16 +1,15 @@ "use client"; -import React from "react"; + import { ColumnDef } from "@tanstack/react-table"; -import { Badge, badgeVariants } from "@repo/ui/components/shared/badge"; +import { Badge, badgeVariants } from "@/src/components/ui/badge"; import { statuses, types } from "./data"; -import { DataTableColumnHeader } from "@repo/ui/components/common/data-table/data-table-column-header"; -import { PersonalTransactions } from "../../..//types/interfaces/TransactionInterfaces"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { formatNumber } from "@repo/ui/lib/utils"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; +import { DataTableColumnHeader } from "../common/data-table/data-table-column-header"; +import { PersonalTransactions } from "@/src/types/interfaces/TransactionInterfaces"; +import TruncatedAddress from "../common/truncated-address"; +import { formatNumber } from "@/src/lib/utils"; import Link from "next/link"; +import { EyeOpenIcon } from "@radix-ui/react-icons"; export const columns: ColumnDef[] = [ { @@ -20,16 +19,11 @@ export const columns: ColumnDef[] = [ ), cell: ({ row }) => { return ( - +
    #{Number(row.getValue("blockNumber"))} - +
    ); }, enableSorting: false, @@ -41,14 +35,7 @@ export const columns: ColumnDef[] = [ ), cell: ({ row }) => { - return ( - - ); + return ; }, enableSorting: false, enableHiding: false, @@ -59,14 +46,7 @@ export const columns: ColumnDef[] = [ ), cell: ({ row }) => { - return ( - - ); + return ; }, enableSorting: false, enableHiding: false, @@ -145,4 +125,14 @@ export const columns: ColumnDef[] = [ return value.includes(row.getValue(id)); }, }, + { + id: "actions", + cell: ({ row }) => { + return ( + + + + ); + }, + }, ]; diff --git a/tools/tenscan/frontend/src/components/modules/personal/data.tsx b/tools/tenscan/frontend/src/components/modules/personal/data.tsx index c09678e777..a1797c82a9 100644 --- a/tools/tenscan/frontend/src/components/modules/personal/data.tsx +++ b/tools/tenscan/frontend/src/components/modules/personal/data.tsx @@ -1,4 +1,4 @@ -import { CheckIcon, Cross2Icon } from "@repo/ui/components/shared/react-icons"; +import { CheckIcon, Cross2Icon } from "@radix-ui/react-icons"; export const statuses = [ { diff --git a/tools/tenscan/frontend/src/components/modules/personal/index.tsx b/tools/tenscan/frontend/src/components/modules/personal/index.tsx index 948c0e4722..03630d4c07 100644 --- a/tools/tenscan/frontend/src/components/modules/personal/index.tsx +++ b/tools/tenscan/frontend/src/components/modules/personal/index.tsx @@ -1,15 +1,25 @@ import React from "react"; import { columns } from "@/src/components/modules/personal/columns"; -import { DataTable } from "@repo/ui/components/common/data-table/data-table"; +import { DataTable } from "@/src/components/modules/common/data-table/data-table"; import { useTransactionsService } from "@/src/services/useTransactionsService"; export default function PersonalTransactions() { - const { personalTxns, personalTxnsLoading } = useTransactionsService(); + const { personalTxns, setNoPolling, personalTxnsLoading } = + useTransactionsService(); const { Receipts, Total } = personalTxns || { Receipts: [], Total: 0, }; + React.useEffect(() => { + setNoPolling(true); + + return () => { + setNoPolling(false); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return ( <>
    diff --git a/tools/tenscan/frontend/src/components/modules/personal/personal-txn-details.tsx b/tools/tenscan/frontend/src/components/modules/personal/personal-txn-details.tsx index 0e33d3225e..00e174f8e6 100644 --- a/tools/tenscan/frontend/src/components/modules/personal/personal-txn-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/personal/personal-txn-details.tsx @@ -1,27 +1,19 @@ -import React, { useState } from "react"; -import KeyValueItem, { - KeyValueList, -} from "@repo/ui/components/shared/key-value"; +import TruncatedAddress from "../common/truncated-address"; +import KeyValueItem, { KeyValueList } from "@/src/components/ui/key-value"; +import { Badge } from "@/src/components/ui/badge"; import { PersonalTransactionType, TransactionReceipt, TransactionType, -} from "../../../types/interfaces/TransactionInterfaces"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { Badge } from "@repo/ui/components/shared/badge"; -import { BadgeType } from "@repo/ui/lib/enums/badge"; -import { Button } from "@repo/ui/components/shared/button"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; +} from "@/src/types/interfaces/TransactionInterfaces"; +import { BadgeType } from "@/src/types/interfaces"; +import Link from "next/link"; export function PersonalTxnDetailsComponent({ transactionDetails, }: { transactionDetails: TransactionReceipt; }) { - const [logsExpanded, setLogsExpanded] = useState(false); - const toggleLogs = () => setLogsExpanded(!logsExpanded); - const getTransactionType = (type: TransactionType) => { switch (type) { case PersonalTransactionType.Legacy: @@ -38,16 +30,14 @@ export function PersonalTxnDetailsComponent({ }; return ( -
    +
    } /> @@ -56,16 +46,14 @@ export function PersonalTxnDetailsComponent({ value={ } /> + {Number(transactionDetails?.transactionIndex)} } @@ -73,7 +61,13 @@ export function PersonalTxnDetailsComponent({ + {getTransactionType(transactionDetails?.type)} } @@ -92,26 +86,27 @@ export function PersonalTxnDetailsComponent({ } /> + + {Number(transactionDetails?.blockNumber)} - + } /> - {Number(transactionDetails?.gasUsed)} + + {Number(transactionDetails?.gasUsed)}{" "} } /> + {Number(transactionDetails?.cumulativeGasUsed)} } @@ -119,7 +114,7 @@ export function PersonalTxnDetailsComponent({ + {Number(transactionDetails?.effectiveGasPrice)} } @@ -135,7 +130,10 @@ export function PersonalTxnDetailsComponent({ + } /> } /> + 0 ? (
    - - {logsExpanded && ( -
    - {transactionDetails?.logs.map((log, index) => ( -
    - - } - /> - } - /> - - } - /> - - - {log.removed ? "Yes" : "No"} - + {transactionDetails?.logs.map((log, index) => ( +
    + + } + /> + } + /> + + } + /> + + - - {log.topics.map((topic, index) => ( -
    - -
    - ))} + > + {log.removed ? "Yes" : "No"} + + } + /> + + {log.topics.map((topic, index) => ( +
    + } + />
    - } - /> - - } - /> - - {Number(transactionDetails?.transactionIndex)} - - } - isLastItem + ))} +
    + } + /> + -
    -
    - ))} + } + /> + + {Number(transactionDetails?.transactionIndex)} + + } + isLastItem + /> +
    - )} + ))}
    ) : ( - "No logs found." + "No logs found" ) } isLastItem diff --git a/tools/tenscan/frontend/src/components/modules/resources/decrypt.tsx b/tools/tenscan/frontend/src/components/modules/resources/decrypt.tsx index a4379d7d08..98dfd9cbbc 100644 --- a/tools/tenscan/frontend/src/components/modules/resources/decrypt.tsx +++ b/tools/tenscan/frontend/src/components/modules/resources/decrypt.tsx @@ -1,29 +1,26 @@ import React, { useEffect, useState } from "react"; -import { - Alert, - AlertTitle, - AlertDescription, -} from "@repo/ui/components/shared/alert"; -import { Badge } from "@repo/ui/components/shared/badge"; -import { Button } from "@repo/ui/components/shared/button"; +import { Alert, AlertTitle, AlertDescription } from "@/src/components/ui/alert"; +import { Badge } from "@/src/components/ui/badge"; +import { Button } from "@/src/components/ui/button"; import { Card, CardHeader, CardTitle, CardContent, -} from "@repo/ui/components/shared/card"; -import { Textarea } from "@repo/ui/components/shared/textarea"; +} from "@/src/components/ui/card"; +import { Textarea } from "@/src/components/ui/textarea"; import { currentEncryptedKey } from "@/src/lib/constants"; -import { CopyIcon, Terminal } from "@repo/ui/components/shared/react-icons"; +import { CopyIcon } from "@radix-ui/react-icons"; +import { Terminal } from "lucide-react"; import { useRouter } from "next/router"; import JSONPretty from "react-json-pretty"; import { useRollupsService } from "@/src/services/useRollupsService"; import { Tooltip, - TooltipContent, TooltipProvider, TooltipTrigger, -} from "@repo/ui/components/shared/tooltip"; + TooltipContent, +} from "@radix-ui/react-tooltip"; export default function Decrypt() { const router = useRouter(); diff --git a/tools/tenscan/frontend/src/components/modules/resources/verified-data/VerifiedContracts.tsx b/tools/tenscan/frontend/src/components/modules/resources/verified-data/VerifiedContracts.tsx index 220d54a4e7..2554da9a02 100644 --- a/tools/tenscan/frontend/src/components/modules/resources/verified-data/VerifiedContracts.tsx +++ b/tools/tenscan/frontend/src/components/modules/resources/verified-data/VerifiedContracts.tsx @@ -5,18 +5,18 @@ import { TableHead, TableBody, TableCell, -} from "@repo/ui/components/shared/table"; -import { Table } from "@repo/ui/components/shared/table"; +} from "@/src/components/ui/table"; +import { Table } from "@/src/components/ui/table"; import { useContractsService } from "@/src/services/useContractsService"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { Badge } from "@repo/ui/components/shared/badge"; +import TruncatedAddress from "../../common/truncated-address"; +import { Badge } from "@/src/components/ui/badge"; import { Card, CardHeader, CardTitle, CardContent, -} from "@repo/ui/components/shared/card"; -import { Separator } from "@repo/ui/components/shared/separator"; +} from "@/src/components/ui/card"; +import { Separator } from "@/src/components/ui/separator"; export default function VerifiedContracts() { const { formattedContracts } = useContractsService(); diff --git a/tools/tenscan/frontend/src/components/modules/resources/verified-data/VerifiedSequencerData.tsx b/tools/tenscan/frontend/src/components/modules/resources/verified-data/VerifiedSequencerData.tsx index 4f5ae0adcf..0cbdd962a3 100644 --- a/tools/tenscan/frontend/src/components/modules/resources/verified-data/VerifiedSequencerData.tsx +++ b/tools/tenscan/frontend/src/components/modules/resources/verified-data/VerifiedSequencerData.tsx @@ -5,18 +5,18 @@ import { TableHead, TableBody, TableCell, -} from "@repo/ui/components/shared/table"; -import { Table } from "@repo/ui/components/shared/table"; +} from "@/src/components/ui/table"; +import { Table } from "@/src/components/ui/table"; import { useContractsService } from "@/src/services/useContractsService"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { Badge } from "@repo/ui/components/shared/badge"; +import TruncatedAddress from "../../common/truncated-address"; +import { Badge } from "@/src/components/ui/badge"; import { Card, CardHeader, CardTitle, CardContent, -} from "@repo/ui/components/shared/card"; -import { Separator } from "@repo/ui/components/shared/separator"; +} from "@/src/components/ui/card"; +import { Separator } from "@/src/components/ui/separator"; export default function VerifiedSequencerData() { const { sequencerData } = useContractsService(); diff --git a/tools/tenscan/frontend/src/components/modules/rollups/columns.tsx b/tools/tenscan/frontend/src/components/modules/rollups/columns.tsx index 429f4d6066..fe76d6fa3c 100644 --- a/tools/tenscan/frontend/src/components/modules/rollups/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/rollups/columns.tsx @@ -1,14 +1,12 @@ "use client"; import { ColumnDef } from "@tanstack/react-table"; -import { DataTableColumnHeader } from "@repo/ui/components/common/data-table/data-table-column-header"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { formatTimeAgo } from "@repo/ui/lib/utils"; +import { DataTableColumnHeader } from "../common/data-table/data-table-column-header"; +import TruncatedAddress from "../common/truncated-address"; +import { formatTimeAgo } from "@/src/lib/utils"; import Link from "next/link"; -import { EyeOpenIcon } from "@repo/ui/components/shared/react-icons"; +import { EyeOpenIcon } from "@radix-ui/react-icons"; import { Rollup } from "@/src/types/interfaces/RollupInterfaces"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; export const columns: ColumnDef[] = [ { @@ -35,9 +33,10 @@ export const columns: ColumnDef[] = [ return ( ); }, @@ -81,9 +80,7 @@ export const columns: ColumnDef[] = [ return (
    @@ -105,9 +102,7 @@ export const columns: ColumnDef[] = [ return (
    @@ -124,9 +119,7 @@ export const columns: ColumnDef[] = [ id: "actions", cell: ({ row }) => { return ( - + ); diff --git a/tools/tenscan/frontend/src/components/modules/rollups/constants.tsx b/tools/tenscan/frontend/src/components/modules/rollups/constants.tsx index 793b3242f3..2ab030f09f 100644 --- a/tools/tenscan/frontend/src/components/modules/rollups/constants.tsx +++ b/tools/tenscan/frontend/src/components/modules/rollups/constants.tsx @@ -4,7 +4,7 @@ import { ArrowUpIcon, CheckCircledIcon, ClockIcon, -} from "@repo/ui/components/shared/react-icons"; +} from "@radix-ui/react-icons"; export const labels = [ { diff --git a/tools/tenscan/frontend/src/components/modules/rollups/rollup-details.tsx b/tools/tenscan/frontend/src/components/modules/rollups/rollup-details.tsx index 239c6082c4..b53eb0e81e 100644 --- a/tools/tenscan/frontend/src/components/modules/rollups/rollup-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/rollups/rollup-details.tsx @@ -1,13 +1,8 @@ -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import KeyValueItem, { - KeyValueList, -} from "@repo/ui/components/shared/key-value"; -import { formatTimeAgo, formatTimestampToDate } from "@repo/ui/lib/utils"; -import Link from "next/link"; +import TruncatedAddress from "../common/truncated-address"; +import KeyValueItem, { KeyValueList } from "@/src/components/ui/key-value"; +import { formatTimeAgo } from "@/src/lib/utils"; import { Rollup } from "@/src/types/interfaces/RollupInterfaces"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; -import { Badge } from "@repo/ui/components/shared/badge"; +import Link from "next/link"; export function RollupDetailsComponent({ rollupDetails, @@ -20,23 +15,14 @@ export function RollupDetailsComponent({ - {formatTimeAgo(rollupDetails?.Timestamp) + - " - " + - formatTimestampToDate(rollupDetails?.Timestamp)} - - } + value={formatTimeAgo(rollupDetails?.Timestamp)} /> } /> @@ -45,26 +31,19 @@ export function RollupDetailsComponent({ value={ } /> - } + value={} /> {"#" + rollupDetails?.FirstSeq} @@ -75,9 +54,7 @@ export function RollupDetailsComponent({ label="Last Batch Seq No." value={ {"#" + rollupDetails?.LastSeq} @@ -89,17 +66,13 @@ export function RollupDetailsComponent({ value={ } /> + } /> {"#" + msg.Sequence} diff --git a/tools/tenscan/frontend/src/components/modules/transactions/columns.tsx b/tools/tenscan/frontend/src/components/modules/transactions/columns.tsx index d09df4d386..a615dad2cb 100644 --- a/tools/tenscan/frontend/src/components/modules/transactions/columns.tsx +++ b/tools/tenscan/frontend/src/components/modules/transactions/columns.tsx @@ -1,16 +1,14 @@ "use client"; import { ColumnDef } from "@tanstack/react-table"; -import { Badge } from "@repo/ui/components/shared/badge"; +import { Badge } from "@/src/components/ui/badge"; import { statuses } from "./constants"; -import { DataTableColumnHeader } from "@repo/ui/components/common/data-table/data-table-column-header"; +import { DataTableColumnHeader } from "../common/data-table/data-table-column-header"; import { Transaction } from "@/src/types/interfaces/TransactionInterfaces"; -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import { formatTimeAgo } from "@repo/ui/lib/utils"; +import TruncatedAddress from "../common/truncated-address"; +import { formatTimeAgo } from "@/src/lib/utils"; import Link from "next/link"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; export const columns: ColumnDef[] = [ { @@ -62,9 +60,7 @@ export const columns: ColumnDef[] = [ return ( ); }, diff --git a/tools/tenscan/frontend/src/components/modules/transactions/constants.tsx b/tools/tenscan/frontend/src/components/modules/transactions/constants.tsx index 793b3242f3..2ab030f09f 100644 --- a/tools/tenscan/frontend/src/components/modules/transactions/constants.tsx +++ b/tools/tenscan/frontend/src/components/modules/transactions/constants.tsx @@ -4,7 +4,7 @@ import { ArrowUpIcon, CheckCircledIcon, ClockIcon, -} from "@repo/ui/components/shared/react-icons"; +} from "@radix-ui/react-icons"; export const labels = [ { diff --git a/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx b/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx index dc9ab9aea8..9b1ba535b8 100644 --- a/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx +++ b/tools/tenscan/frontend/src/components/modules/transactions/transaction-details.tsx @@ -1,14 +1,10 @@ -import TruncatedAddress from "@repo/ui/components/common/truncated-address"; -import KeyValueItem, { - KeyValueList, -} from "@repo/ui/components/shared/key-value"; -import { formatTimeAgo, formatTimestampToDate } from "@repo/ui/lib/utils"; -import { BadgeType } from "@repo/ui/lib/enums/badge"; -import { Badge } from "@repo/ui/components/shared/badge"; +import TruncatedAddress from "../common/truncated-address"; +import KeyValueItem, { KeyValueList } from "@/src/components/ui/key-value"; +import { formatTimeAgo } from "@/src/lib/utils"; +import { Badge } from "@/src/components/ui/badge"; import { Transaction } from "@/src/types/interfaces/TransactionInterfaces"; +import { BadgeType } from "@/src/types/interfaces"; import Link from "next/link"; -import { pathToUrl } from "@/src/routes/router"; -import { pageLinks } from "@/src/routes"; export function TransactionDetailsComponent({ transactionDetails, @@ -22,9 +18,7 @@ export function TransactionDetailsComponent({ label="Batch Height" value={ {"#" + Number(transactionDetails?.BatchHeight)} @@ -36,19 +30,13 @@ export function TransactionDetailsComponent({ value={ } /> - {formatTimeAgo(transactionDetails?.BatchTimestamp) + - " - " + - formatTimestampToDate(transactionDetails?.BatchTimestamp)} - - } + value={formatTimeAgo(transactionDetails?.BatchTimestamp)} /> (null); + +export const useWalletConnection = (): WalletConnectionContextType => { + const context = useContext(WalletConnectionContext); + if (!context) { + throw new Error( + "useWalletConnection must be used within a WalletConnectionProvider" + ); + } + return context; +}; + +export const WalletConnectionProvider = ({ + children, +}: WalletConnectionProviderProps) => { + const [walletConnected, setWalletConnected] = useState(false); + const [walletAddress, setWalletAddress] = useState(null); + const [provider, setProvider] = + useState(null); + + const connectWallet = async () => { + if (ethereum) { + const ethProvider = new ethers.providers.Web3Provider(ethereum); + setProvider(ethProvider); + + try { + await ethProvider.send("eth_requestAccounts", []); + const signer = ethProvider.getSigner(); + const address = await signer.getAddress(); + setWalletAddress(address); + setWalletConnected(true); + } catch (error: any) { + showToast( + ToastType.DESTRUCTIVE, + "Error connecting to wallet:" + error?.message + ); + } + } else { + showToast( + ToastType.DESTRUCTIVE, + "No ethereum object found. Please install MetaMask!" + ); + } + }; + + const disconnectWallet = () => { + if (provider) { + provider.removeAllListeners(); + setWalletConnected(false); + setWalletAddress(null); + setProvider(null); + } + }; + + useEffect(() => { + if (!ethereum) { + return; + } + + const handleAccountsChanged = (accounts: string[]) => { + if (accounts.length === 0) { + showToast(ToastType.DESTRUCTIVE, "Please connect to MetaMask."); + } else if (accounts[0] !== walletAddress) { + setWalletAddress(accounts[0]); + } + }; + + ethereum.on("accountsChanged", handleAccountsChanged); + return () => { + if (!ethereum) return; + ethereum.removeListener("accountsChanged", handleAccountsChanged); + }; + }); + + const walletConnectionContextValue: WalletConnectionContextType = { + provider, + walletConnected, + walletAddress, + connectWallet, + disconnectWallet, + }; + + return ( + + {children} + + ); +}; diff --git a/tools/tenscan/frontend/src/components/search.tsx b/tools/tenscan/frontend/src/components/search.tsx index aa4091d2b5..72c09e031c 100644 --- a/tools/tenscan/frontend/src/components/search.tsx +++ b/tools/tenscan/frontend/src/components/search.tsx @@ -1,4 +1,4 @@ -import { Input } from "@repo/ui/components/shared/input"; +import { Input } from "@/src/components/ui/input"; export function Search() { return ( diff --git a/tools/tenscan/frontend/src/components/ui/alert.tsx b/tools/tenscan/frontend/src/components/ui/alert.tsx new file mode 100644 index 0000000000..85cfe674b7 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/alert.tsx @@ -0,0 +1,64 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/src/lib/utils"; + +const alertVariants = cva( + "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + { + variants: { + variant: { + default: "bg-background text-foreground", + destructive: + "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + info: "border-info/50 text-info dark:border-info [&>svg]:text-info", + success: + "border-success/50 text-success dark:border-success [&>svg]:text-success", + warning: + "border-warning/50 text-warning dark:border-warning [&>svg]:text-warning", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +const Alert = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & VariantProps +>(({ className, variant, ...props }, ref) => ( +
    +)); +Alert.displayName = "Alert"; + +const AlertTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)); +AlertTitle.displayName = "AlertTitle"; + +const AlertDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)); +AlertDescription.displayName = "AlertDescription"; + +export { Alert, AlertTitle, AlertDescription }; diff --git a/tools/tenscan/frontend/src/components/ui/avatar.tsx b/tools/tenscan/frontend/src/components/ui/avatar.tsx new file mode 100644 index 0000000000..dcc25adf49 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/avatar.tsx @@ -0,0 +1,54 @@ +import * as React from "react"; +import * as AvatarPrimitive from "@radix-ui/react-avatar"; + +import { cn } from "@/src/lib/utils"; + +type AvatarImageProps = React.ComponentPropsWithoutRef< + typeof AvatarPrimitive.Image +> & { + src?: string | React.ComponentType; +}; + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = React.forwardRef< + React.ElementRef, + AvatarImageProps +>(({ className, ...props }, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/tools/tenscan/frontend/src/components/ui/badge.tsx b/tools/tenscan/frontend/src/components/ui/badge.tsx new file mode 100644 index 0000000000..cac0bf960b --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/badge.tsx @@ -0,0 +1,37 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/src/lib/utils"; + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: "border-transparent bg-primary hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + success: + "border-transparent bg-success text-success-foreground hover:bg-success/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
    + ); +} + +export { Badge, badgeVariants }; diff --git a/tools/tenscan/frontend/src/components/ui/button.tsx b/tools/tenscan/frontend/src/components/ui/button.tsx new file mode 100644 index 0000000000..aa0d241a58 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/button.tsx @@ -0,0 +1,58 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/src/lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + clear: "bg-transparent text-primary-foreground outline-none", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10 p-1", + wrap: "h-full w-full", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + } +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/tools/tenscan/frontend/src/components/ui/calendar.tsx b/tools/tenscan/frontend/src/components/ui/calendar.tsx new file mode 100644 index 0000000000..0b2f5e83e6 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/calendar.tsx @@ -0,0 +1,62 @@ +import * as React from "react"; +import { ChevronLeft, ChevronRight } from "lucide-react"; +import { DayPicker } from "react-day-picker"; + +import { cn } from "@/src/lib/utils"; +import { buttonVariants } from "@/src/components/ui/button"; + +export type CalendarProps = React.ComponentProps; + +function Calendar({ + className, + classNames, + showOutsideDays = true, + ...props +}: CalendarProps) { + return ( + , + IconRight: ({ ...props }) => , + }} + {...props} + /> + ); +} +Calendar.displayName = "Calendar"; + +export { Calendar }; diff --git a/tools/tenscan/frontend/src/components/ui/card.tsx b/tools/tenscan/frontend/src/components/ui/card.tsx new file mode 100644 index 0000000000..3307589084 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/card.tsx @@ -0,0 +1,56 @@ +import * as React from 'react' + +import { cn } from '@/src/lib/utils' + +const Card = React.forwardRef>( + ({ className, ...props }, ref) => ( +
    + ) +) +Card.displayName = 'Card' + +const CardHeader = React.forwardRef>( + ({ className, ...props }, ref) => ( +
    + ) +) +CardHeader.displayName = 'CardHeader' + +const CardTitle = React.forwardRef>( + ({ className, ...props }, ref) => ( +

    + ) +) +CardTitle.displayName = 'CardTitle' + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

    +)) +CardDescription.displayName = 'CardDescription' + +const CardContent = React.forwardRef>( + ({ className, ...props }, ref) => ( +

    + ) +) +CardContent.displayName = 'CardContent' + +const CardFooter = React.forwardRef>( + ({ className, ...props }, ref) => ( +
    + ) +) +CardFooter.displayName = 'CardFooter' + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/tools/tenscan/frontend/src/components/ui/checkbox.tsx b/tools/tenscan/frontend/src/components/ui/checkbox.tsx new file mode 100644 index 0000000000..e4f571b0ce --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/checkbox.tsx @@ -0,0 +1,28 @@ +import * as React from "react"; +import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; +import { Check } from "lucide-react"; + +import { cn } from "@/src/lib/utils"; + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)); +Checkbox.displayName = CheckboxPrimitive.Root.displayName; + +export { Checkbox }; diff --git a/tools/tenscan/frontend/src/components/ui/command.tsx b/tools/tenscan/frontend/src/components/ui/command.tsx new file mode 100644 index 0000000000..fd81fd9b4c --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/command.tsx @@ -0,0 +1,153 @@ +import * as React from "react"; +import { DialogProps } from "@radix-ui/react-dialog"; +import { Command as CommandPrimitive } from "cmdk"; +import { Search } from "lucide-react"; + +import { cn } from "@/src/lib/utils"; +import { Dialog, DialogContent } from "@/src/components/ui/dialog"; + +const Command = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Command.displayName = CommandPrimitive.displayName; + +interface CommandDialogProps extends DialogProps {} + +const CommandDialog = ({ children, ...props }: CommandDialogProps) => { + return ( + + + + {children} + + + + ); +}; + +const CommandInput = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
    + + +
    +)); + +CommandInput.displayName = CommandPrimitive.Input.displayName; + +const CommandList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandList.displayName = CommandPrimitive.List.displayName; + +const CommandEmpty = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName; + +const CommandGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandGroup.displayName = CommandPrimitive.Group.displayName; + +const CommandSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +CommandSeparator.displayName = CommandPrimitive.Separator.displayName; + +const CommandItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandItem.displayName = CommandPrimitive.Item.displayName; + +const CommandShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +CommandShortcut.displayName = "CommandShortcut"; + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +}; diff --git a/tools/tenscan/frontend/src/components/ui/dialog.tsx b/tools/tenscan/frontend/src/components/ui/dialog.tsx new file mode 100644 index 0000000000..973b5c4088 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/dialog.tsx @@ -0,0 +1,102 @@ +import * as React from 'react' +import * as DialogPrimitive from '@radix-ui/react-dialog' +import { X } from 'lucide-react' + +import { cn } from '@/src/lib/utils' + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
    +) +DialogHeader.displayName = 'DialogHeader' + +const DialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( +
    +) +DialogFooter.displayName = 'DialogFooter' + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription +} diff --git a/tools/tenscan/frontend/src/components/ui/dropdown-menu.tsx b/tools/tenscan/frontend/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000000..f08b9a2d01 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,183 @@ +import * as React from 'react' +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu' +import { Check, ChevronRight, Circle } from 'lucide-react' + +import { cn } from '@/src/lib/utils' + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { + return +} +DropdownMenuShortcut.displayName = 'DropdownMenuShortcut' + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup +} diff --git a/tools/tenscan/frontend/src/components/ui/external-link.tsx b/tools/tenscan/frontend/src/components/ui/external-link.tsx new file mode 100644 index 0000000000..13366137ea --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/external-link.tsx @@ -0,0 +1,25 @@ +import { ExternalLinkIcon } from "@radix-ui/react-icons"; +import React from "react"; + +const ExternalLink = ({ + href, + children, + className, +}: { + href: string; + children: React.ReactNode; + className?: string; +}) => { + return ( + + {children} + + ); +}; + +export default ExternalLink; diff --git a/tools/tenscan/frontend/src/components/ui/input.tsx b/tools/tenscan/frontend/src/components/ui/input.tsx new file mode 100644 index 0000000000..e23cdfa1a8 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/input.tsx @@ -0,0 +1,24 @@ +import * as React from 'react' + +import { cn } from '@/src/lib/utils' + +export interface InputProps extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = 'Input' + +export { Input } diff --git a/tools/tenscan/frontend/src/components/ui/key-value.tsx b/tools/tenscan/frontend/src/components/ui/key-value.tsx new file mode 100644 index 0000000000..540e3a7ce3 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/key-value.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { Separator } from "./separator"; + +export const KeyValueList = ({ children }: { children: React.ReactNode }) => ( +
      {children}
    +); + +export const KeyValueItem = ({ + label, + value, + isLastItem, +}: { + label?: string; + value: string | number | React.ReactNode; + isLastItem?: boolean; +}) => ( +
  • +
    + {label && {label}} + {value} +
    + {!isLastItem && } +
  • +); + +export default KeyValueItem; diff --git a/tools/tenscan/frontend/src/components/ui/label.tsx b/tools/tenscan/frontend/src/components/ui/label.tsx new file mode 100644 index 0000000000..27adca2cea --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/label.tsx @@ -0,0 +1,19 @@ +import * as React from 'react' +import * as LabelPrimitive from '@radix-ui/react-label' +import { cva, type VariantProps } from 'class-variance-authority' + +import { cn } from '@/src/lib/utils' + +const labelVariants = cva( + 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70' +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/tools/tenscan/frontend/src/components/ui/navigation-menu.tsx b/tools/tenscan/frontend/src/components/ui/navigation-menu.tsx new file mode 100644 index 0000000000..1e7b75005f --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/navigation-menu.tsx @@ -0,0 +1,120 @@ +import * as React from 'react' +import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu' +import { cva } from 'class-variance-authority' +import { ChevronDown } from 'lucide-react' + +import { cn } from '@/src/lib/utils' + +const NavigationMenu = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children} + + +)) +NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName + +const NavigationMenuList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName + +const NavigationMenuItem = NavigationMenuPrimitive.Item + +const navigationMenuTriggerStyle = cva( + 'group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50' +) + +const NavigationMenuTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children}{' '} + +)) +NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName + +const NavigationMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName + +const NavigationMenuLink = NavigationMenuPrimitive.Link + +const NavigationMenuViewport = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
    + +
    +)) +NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName + +const NavigationMenuIndicator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +
    + +)) +NavigationMenuIndicator.displayName = NavigationMenuPrimitive.Indicator.displayName + +export { + navigationMenuTriggerStyle, + NavigationMenu, + NavigationMenuList, + NavigationMenuItem, + NavigationMenuContent, + NavigationMenuTrigger, + NavigationMenuLink, + NavigationMenuIndicator, + NavigationMenuViewport +} diff --git a/tools/tenscan/frontend/src/components/ui/popover.tsx b/tools/tenscan/frontend/src/components/ui/popover.tsx new file mode 100644 index 0000000000..18b61979cf --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/popover.tsx @@ -0,0 +1,29 @@ +import * as React from 'react' +import * as PopoverPrimitive from '@radix-ui/react-popover' + +import { cn } from '@/src/lib/utils' + +const Popover = PopoverPrimitive.Root + +const PopoverTrigger = PopoverPrimitive.Trigger + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( + + + +)) +PopoverContent.displayName = PopoverPrimitive.Content.displayName + +export { Popover, PopoverTrigger, PopoverContent } diff --git a/tools/tenscan/frontend/src/components/ui/select.tsx b/tools/tenscan/frontend/src/components/ui/select.tsx new file mode 100644 index 0000000000..bb1703edc5 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/select.tsx @@ -0,0 +1,119 @@ +import * as React from 'react' +import * as SelectPrimitive from '@radix-ui/react-select' +import { Check, ChevronDown } from 'lucide-react' + +import { cn } from '@/src/lib/utils' + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = 'popper', ...props }, ref) => ( + + + + {children} + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator +} diff --git a/tools/tenscan/frontend/src/components/ui/separator.tsx b/tools/tenscan/frontend/src/components/ui/separator.tsx new file mode 100644 index 0000000000..fd1ac8931b --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/separator.tsx @@ -0,0 +1,29 @@ +import * as React from "react"; +import * as SeparatorPrimitive from "@radix-ui/react-separator"; + +import { cn } from "@/src/lib/utils"; + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref + ) => ( + + ) +); +Separator.displayName = SeparatorPrimitive.Root.displayName; + +export { Separator }; diff --git a/tools/tenscan/frontend/src/components/ui/skeleton.tsx b/tools/tenscan/frontend/src/components/ui/skeleton.tsx new file mode 100644 index 0000000000..03e4c85986 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/skeleton.tsx @@ -0,0 +1,15 @@ +import { cn } from "@/src/lib/utils" + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
    + ) +} + +export { Skeleton } diff --git a/tools/tenscan/frontend/src/components/ui/spinner.tsx b/tools/tenscan/frontend/src/components/ui/spinner.tsx new file mode 100644 index 0000000000..2948ef451b --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/spinner.tsx @@ -0,0 +1,11 @@ +import React from "react"; + +const Spinner = () => { + return ( +
    +
    +
    + ); +}; + +export default Spinner; diff --git a/tools/tenscan/frontend/src/components/ui/table.tsx b/tools/tenscan/frontend/src/components/ui/table.tsx new file mode 100644 index 0000000000..0b8376b09f --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/table.tsx @@ -0,0 +1,91 @@ +import * as React from 'react' + +import { cn } from '@/src/lib/utils' + +const Table = React.forwardRef>( + ({ className, ...props }, ref) => ( +
    + + + ) +) +Table.displayName = 'Table' + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = 'TableHeader' + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = 'TableBody' + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableFooter.displayName = 'TableFooter' + +const TableRow = React.forwardRef>( + ({ className, ...props }, ref) => ( + + ) +) +TableRow.displayName = 'TableRow' + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)) +TableHead.displayName = 'TableHead' + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = 'TableCell' + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)) +TableCaption.displayName = 'TableCaption' + +export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } diff --git a/tools/tenscan/frontend/src/components/ui/tabs.tsx b/tools/tenscan/frontend/src/components/ui/tabs.tsx new file mode 100644 index 0000000000..47a3925903 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/tabs.tsx @@ -0,0 +1,53 @@ +import * as React from 'react' +import * as TabsPrimitive from '@radix-ui/react-tabs' + +import { cn } from '@/src/lib/utils' + +const Tabs = TabsPrimitive.Root + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsList.displayName = TabsPrimitive.List.displayName + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsContent.displayName = TabsPrimitive.Content.displayName + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/tools/tenscan/frontend/src/components/ui/textarea.tsx b/tools/tenscan/frontend/src/components/ui/textarea.tsx new file mode 100644 index 0000000000..db65d62a57 --- /dev/null +++ b/tools/tenscan/frontend/src/components/ui/textarea.tsx @@ -0,0 +1,24 @@ +import * as React from "react" + +import { cn } from "@/src/lib/utils" + +export interface TextareaProps + extends React.TextareaHTMLAttributes {} + +const Textarea = React.forwardRef( + ({ className, ...props }, ref) => { + return ( +