From 6eb4f0db7e4f1b385a73ad800ce69009c36b49c4 Mon Sep 17 00:00:00 2001 From: Zeeshan Ahmad Date: Sat, 21 Jun 2025 02:46:36 +0500 Subject: [PATCH] feat: use tanstack table for leaderboard --- apps/app/package.json | 1 + apps/app/src/components/Leaderboard.tsx | 419 ++---------------- .../leaderboard/LeaderboardColumns.tsx | 134 ++++++ .../leaderboard/LeaderboardFilters.tsx | 144 ++++++ .../leaderboard/LeaderboardSkeleton.tsx | 60 +++ .../leaderboard/LeaderboardTable.tsx | 111 +++++ apps/app/src/components/leaderboard/index.ts | 7 + apps/app/src/hooks/useLeaderboard.ts | 178 ++++++++ pnpm-lock.yaml | 101 ++--- pnpm-workspace.yaml | 8 +- 10 files changed, 726 insertions(+), 437 deletions(-) create mode 100644 apps/app/src/components/leaderboard/LeaderboardColumns.tsx create mode 100644 apps/app/src/components/leaderboard/LeaderboardFilters.tsx create mode 100644 apps/app/src/components/leaderboard/LeaderboardSkeleton.tsx create mode 100644 apps/app/src/components/leaderboard/LeaderboardTable.tsx create mode 100644 apps/app/src/components/leaderboard/index.ts create mode 100644 apps/app/src/hooks/useLeaderboard.ts diff --git a/apps/app/package.json b/apps/app/package.json index f2cd386e..7f258a07 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -31,6 +31,7 @@ "@tailwindcss/typography": "^0.5.15", "@tanstack/react-query": "^5.64.1", "@tanstack/react-router": "1.97.0", + "@tanstack/react-table": "^8.21.3", "autoprefixer": "^10.4.20", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/apps/app/src/components/Leaderboard.tsx b/apps/app/src/components/Leaderboard.tsx index 8006469b..eb145265 100644 --- a/apps/app/src/components/Leaderboard.tsx +++ b/apps/app/src/components/Leaderboard.tsx @@ -1,17 +1,16 @@ -import { Link } from "@tanstack/react-router"; -import { ChevronDown, ChevronUp, Search } from "lucide-react"; -import { useEffect, useMemo, useRef, useState } from "react"; -import { LeaderboardEntry, useAllFeeds } from "../lib/api"; +import React from "react"; +import { LeaderboardEntry } from "../lib/api"; import { Container } from "./Container"; -import { UserLink } from "./FeedItem"; import { Hero } from "./Hero"; +import { useLeaderboard } from "../hooks/useLeaderboard"; +import { LeaderboardFilters, LeaderboardTable } from "./leaderboard"; interface LeaderboardSearch { feed: string; timeframe: string; } -export default function Leaderboard({ +export default React.memo(function Leaderboard({ search, leaderboard, isLoading, @@ -22,382 +21,54 @@ export default function Leaderboard({ isLoading: boolean; error: Error | null; }) { - const [expandedRows, setExpandedRows] = useState([]); - const [searchQuery, setSearchQuery] = useState(null); - const [showFeedDropdown, setShowFeedDropdown] = useState(false); - const [showTimeDropdown, setShowTimeDropdown] = useState(false); - const { data: allFeeds = [] } = useAllFeeds(); - const feedDropdownRef = useRef(null); - const timeDropdownRef = useRef(null); - - const timeOptions = [ - { label: "All Time", value: "all" }, - { label: "This Month", value: "month" }, - { label: "This Week", value: "week" }, - { label: "Today", value: "today" }, - ]; - - const feeds = useMemo(() => { - return [ - { - label: "All Feeds", - value: "all feeds", - }, - ...( - allFeeds.map((feed) => ({ - label: feed.name, - value: feed.id, - })) || [] - ).filter((feed) => feed.value !== "all"), - ]; - }, [allFeeds]); - - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - feedDropdownRef.current && - !feedDropdownRef.current.contains(event.target as Node) - ) { - setShowFeedDropdown(false); - } - if ( - timeDropdownRef.current && - !timeDropdownRef.current.contains(event.target as Node) - ) { - setShowTimeDropdown(false); - } - }; - - document.addEventListener("mousedown", handleClickOutside); - return () => document.removeEventListener("mousedown", handleClickOutside); - }, []); - - const toggleRow = (index: number) => { - setExpandedRows((prev) => - prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index], - ); - }; - - const handleSearch = (e: React.ChangeEvent) => { - setSearchQuery(e.target.value); - }; - - const filteredLeaderboard = leaderboard?.filter((item) => { - const searchTerm = searchQuery?.toLowerCase(); - const feedFilter = - search.feed === "all feeds" - ? true - : item.feedSubmissions?.some((feed) => feed.feedId === search.feed); - - const matchesSearch = - !searchTerm || - item.curatorUsername?.toLowerCase().includes(searchTerm) || - item.feedSubmissions?.some((feed) => - feed.feedId?.toLowerCase().includes(searchTerm), - ); - - return feedFilter && matchesSearch; - }); - - // Map the filtered items to include their original index - const filteredLeaderboardWithRanks = filteredLeaderboard?.map((item) => { - const originalIndex = leaderboard?.findIndex( - (entry) => entry.curatorId === item.curatorId, - ); - return { - ...item, - originalRank: originalIndex !== undefined ? originalIndex + 1 : 0, - }; - }); + const { + searchQuery, + showFeedDropdown, + showTimeDropdown, + feeds, + timeOptions, + handleSearch, + handleFeedDropdownToggle, + handleTimeDropdownToggle, + handleFeedDropdownClose, + handleTimeDropdownClose, + feedDropdownRef, + timeDropdownRef, + table, + hasData, + } = useLeaderboard(leaderboard, search); return ( -
+
-
-
- - -
-
-
- - {showFeedDropdown && ( -
- {feeds.map((feed, index) => ( - { - setShowFeedDropdown(false); - }} - className={`w-full px-4 py-2 text-left hover:bg-neutral-100 text-sm ${ - search.feed === feed.value ? "bg-neutral-100" : "" - }`} - > - {feed.label} - - ))} -
- )} -
-
- - {showTimeDropdown && ( -
- {timeOptions.map((time) => ( - { - setShowTimeDropdown(false); - }} - className={`w-full px-4 py-2 text-left hover:bg-neutral-100 text-sm ${ - search.timeframe === time.label ? "bg-neutral-100" : "" - }`} - > - {time.label} - - ))} -
- )} -
-
-
- -
-
- - - - - {/* */} - - - - - - - - {isLoading && ( - - - - )} - - {error && ( - - - - )} - - {leaderboard && leaderboard.length === 0 && ( - - - - )} - {filteredLeaderboardWithRanks?.map( - ( - item: LeaderboardEntry & { originalRank: number }, - index, - ) => ( - - - {/* */} - - - - - - ), - )} - -
- Rank - - Curator - - Username - - Approval Rate - - Submissions - - Top Feeds -
-

Loading leaderboard data...

-
-

- Error loading leaderboard: {(error as Error).message} -

-
-

No curator data available.

-
-
- {item.originalRank === 1 && ( - Gold star - 1st place - )} - {item.originalRank === 2 && ( - Silver star - 2nd place - )} - {item.originalRank === 3 && ( - Bronze star - 3rd place - )} -
- - {item.originalRank} - -
-
-
-
- - - {removeSpecialChars(item.curatorUsername)} - -
-
-
- -
-
-
- {item.submissionCount > 0 - ? `${Math.round((item.approvalCount / item.submissionCount) * 100)}%` - : "0%"} -
-
-
- {item.submissionCount} -
-
-
-
- {item.feedSubmissions && - item.feedSubmissions.length > 0 && ( -
- - #{item.feedSubmissions[0].feedId} - - - {item.feedSubmissions[0].count}/ - {item.feedSubmissions[0].totalInFeed} - -
- )} - - {item.feedSubmissions && - item.feedSubmissions.length > 1 && ( - - )} -
- - {item.feedSubmissions && - expandedRows.includes(index) && ( -
- {item.feedSubmissions - .slice(1) - .map((feed, feedIndex) => ( -
-
- - #{feed.feedId} - - - {feed.count}/{feed.totalInFeed} - -
-
- ))} -
- )} -
-
-
-
+ + +
); -} +}); diff --git a/apps/app/src/components/leaderboard/LeaderboardColumns.tsx b/apps/app/src/components/leaderboard/LeaderboardColumns.tsx new file mode 100644 index 00000000..f2c10534 --- /dev/null +++ b/apps/app/src/components/leaderboard/LeaderboardColumns.tsx @@ -0,0 +1,134 @@ +import { ChevronUp } from "lucide-react"; +import { createColumnHelper } from "@tanstack/react-table"; +import { LeaderboardEntry } from "../../lib/api"; +import { UserLink } from "../FeedItem"; + +export interface ExtendedLeaderboardEntry extends LeaderboardEntry { + originalRank: number; +} + +export function createLeaderboardColumns( + expandedRows: number[], + toggleRow: (index: number) => void, +) { + const columnHelper = createColumnHelper(); + + return [ + columnHelper.accessor("originalRank", { + header: "Rank", + cell: (info) => { + const rank = info.getValue(); + return ( +
+ {rank === 1 && ( + Gold star - 1st place + )} + {rank === 2 && ( + Silver star - 2nd place + )} + {rank === 3 && ( + Bronze star - 3rd place + )} +
+ {rank} +
+
+ ); + }, + }), + columnHelper.accessor("curatorUsername", { + header: "Username", + cell: (info) => ( +
+ +
+ ), + }), + columnHelper.accessor( + (row) => { + return row.submissionCount > 0 + ? Math.round((row.approvalCount / row.submissionCount) * 100) + : 0; + }, + { + id: "approvalRate", + header: "Approval Rate", + cell: (info) => ( +
{info.getValue()}%
+ ), + }, + ), + columnHelper.accessor("submissionCount", { + header: "Submissions", + cell: (info) => ( +
+ {info.getValue()} +
+ ), + }), + columnHelper.accessor("feedSubmissions", { + header: "Top Feeds", + cell: (info) => { + const feedSubmissions = info.getValue(); + const rowIndex = info.row.index; + + return ( +
+
+ {feedSubmissions && feedSubmissions.length > 0 && ( +
+ #{feedSubmissions[0].feedId} + + {feedSubmissions[0].count}/{feedSubmissions[0].totalInFeed} + +
+ )} + + {feedSubmissions && feedSubmissions.length > 1 && ( + + )} +
+ + {feedSubmissions && expandedRows.includes(rowIndex) && ( +
+ {feedSubmissions.slice(1).map((feed, feedIndex) => ( +
+
+ #{feed.feedId} + + {feed.count}/{feed.totalInFeed} + +
+
+ ))} +
+ )} +
+ ); + }, + }), + ]; +} diff --git a/apps/app/src/components/leaderboard/LeaderboardFilters.tsx b/apps/app/src/components/leaderboard/LeaderboardFilters.tsx new file mode 100644 index 00000000..812a784f --- /dev/null +++ b/apps/app/src/components/leaderboard/LeaderboardFilters.tsx @@ -0,0 +1,144 @@ +import { Link } from "@tanstack/react-router"; +import { ChevronDown, Search } from "lucide-react"; + +interface Feed { + label: string; + value: string; +} + +interface TimeOption { + label: string; + value: string; +} + +interface LeaderboardFiltersProps { + searchQuery: string | null; + onSearchChange: (e: React.ChangeEvent) => void; + feeds: Feed[]; + timeOptions: TimeOption[]; + search: { + feed: string; + timeframe: string; + }; + showFeedDropdown: boolean; + showTimeDropdown: boolean; + onFeedDropdownToggle: () => void; + onTimeDropdownToggle: () => void; + onFeedDropdownClose: () => void; + onTimeDropdownClose: () => void; + feedDropdownRef: React.RefObject; + timeDropdownRef: React.RefObject; +} + +export function LeaderboardFilters({ + searchQuery, + onSearchChange, + feeds, + timeOptions, + search, + showFeedDropdown, + showTimeDropdown, + onFeedDropdownToggle, + onTimeDropdownToggle, + onFeedDropdownClose, + onTimeDropdownClose, + feedDropdownRef, + timeDropdownRef, +}: LeaderboardFiltersProps) { + return ( +
+
+ + +
+
+
+ + {showFeedDropdown && ( +
+ {feeds.map((feed, index) => ( + + {feed.label} + + ))} +
+ )} +
+
+ + {showTimeDropdown && ( +
+ {timeOptions.map((time) => ( + + {time.label} + + ))} +
+ )} +
+
+
+ ); +} diff --git a/apps/app/src/components/leaderboard/LeaderboardSkeleton.tsx b/apps/app/src/components/leaderboard/LeaderboardSkeleton.tsx new file mode 100644 index 00000000..311e2646 --- /dev/null +++ b/apps/app/src/components/leaderboard/LeaderboardSkeleton.tsx @@ -0,0 +1,60 @@ +import { TableCell, TableRow } from "../ui/table"; + +function SkeletonRow() { + return ( + + {/* Rank column */} + +
+
+
+
+ + + {/* Username column */} + +
+
+
+ + + {/* Approval Rate column */} + +
+
+
+ + + {/* Submissions column */} + +
+
+
+ + + {/* Top Feeds column */} + +
+
+
+
+
+
+ + + ); +} + +interface LeaderboardSkeletonProps { + rows?: number; +} + +export function LeaderboardSkeleton({ rows = 8 }: LeaderboardSkeletonProps) { + return ( + <> + {Array.from({ length: rows }).map((_, index) => ( + + ))} + + ); +} diff --git a/apps/app/src/components/leaderboard/LeaderboardTable.tsx b/apps/app/src/components/leaderboard/LeaderboardTable.tsx new file mode 100644 index 00000000..97098c87 --- /dev/null +++ b/apps/app/src/components/leaderboard/LeaderboardTable.tsx @@ -0,0 +1,111 @@ +import { flexRender, Table as TanStackTable } from "@tanstack/react-table"; +import { ChevronUp, ChevronDown } from "lucide-react"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "../ui/table"; +import { ExtendedLeaderboardEntry } from "./LeaderboardColumns"; +import { LeaderboardSkeleton } from "./LeaderboardSkeleton"; + +interface LeaderboardTableProps { + table: TanStackTable; + isLoading: boolean; + error: Error | null; + hasData: boolean; +} + +export function LeaderboardTable({ + table, + isLoading, + error, + hasData, +}: LeaderboardTableProps) { + return ( +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + +
+ {flexRender( + header.column.columnDef.header, + header.getContext(), + )} + {header.column.getIsSorted() === "asc" ? ( + + ) : header.column.getIsSorted() === "desc" ? ( + + ) : null} +
+
+ ))} +
+ ))} +
+ + {isLoading && } + + {error && ( + + +

Error loading leaderboard: {error.message}

+
+
+ )} + + {!hasData && !isLoading && !error && ( + + +

No curator data available.

+
+
+ )} + + {!isLoading && !error && table.getRowModel().rows.length > 0 + ? table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext(), + )} + + ))} + + )) + : !isLoading && + !error && + table.getRowModel().rows.length === 0 && ( + + +

No matching results found.

+
+
+ )} +
+
+
+
+ ); +} diff --git a/apps/app/src/components/leaderboard/index.ts b/apps/app/src/components/leaderboard/index.ts new file mode 100644 index 00000000..4cf65642 --- /dev/null +++ b/apps/app/src/components/leaderboard/index.ts @@ -0,0 +1,7 @@ +export { LeaderboardFilters } from "./LeaderboardFilters"; +export { LeaderboardTable } from "./LeaderboardTable"; +export { + createLeaderboardColumns, + type ExtendedLeaderboardEntry, +} from "./LeaderboardColumns"; +export { LeaderboardSkeleton } from "./LeaderboardSkeleton"; diff --git a/apps/app/src/hooks/useLeaderboard.ts b/apps/app/src/hooks/useLeaderboard.ts new file mode 100644 index 00000000..c0a28a43 --- /dev/null +++ b/apps/app/src/hooks/useLeaderboard.ts @@ -0,0 +1,178 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { + SortingState, + useReactTable, + getCoreRowModel, + getSortedRowModel, +} from "@tanstack/react-table"; +import { LeaderboardEntry, useAllFeeds } from "../lib/api"; +import { createLeaderboardColumns } from "../components/leaderboard/LeaderboardColumns"; + +interface LeaderboardSearch { + feed: string; + timeframe: string; +} + +export function useLeaderboard( + leaderboard: LeaderboardEntry[], + search: LeaderboardSearch, +) { + const [expandedRows, setExpandedRows] = useState([]); + const [searchQuery, setSearchQuery] = useState(null); + const [debouncedSearchQuery, setDebouncedSearchQuery] = useState< + string | null + >(null); + const [showFeedDropdown, setShowFeedDropdown] = useState(false); + const [showTimeDropdown, setShowTimeDropdown] = useState(false); + const [sorting, setSorting] = useState([]); + const { data: allFeeds = [] } = useAllFeeds(); + const feedDropdownRef = useRef(null); + const timeDropdownRef = useRef(null); + + const timeOptions = [ + { label: "All Time", value: "all" }, + { label: "This Month", value: "month" }, + { label: "This Week", value: "week" }, + { label: "Today", value: "today" }, + ]; + + const feeds = useMemo(() => { + return [ + { + label: "All Feeds", + value: "all feeds", + }, + ...( + allFeeds.map((feed) => ({ + label: feed.name, + value: feed.id, + })) || [] + ).filter((feed) => feed.value !== "all"), + ]; + }, [allFeeds]); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + feedDropdownRef.current && + !feedDropdownRef.current.contains(event.target as Node) + ) { + setShowFeedDropdown(false); + } + if ( + timeDropdownRef.current && + !timeDropdownRef.current.contains(event.target as Node) + ) { + setShowTimeDropdown(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + // Debounce search query + useEffect(() => { + const timer = setTimeout(() => { + setDebouncedSearchQuery(searchQuery); + }, 300); + + return () => clearTimeout(timer); + }, [searchQuery]); + + const toggleRow = useCallback((index: number) => { + setExpandedRows((prev) => + prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index], + ); + }, []); + + const handleSearch = useCallback((e: React.ChangeEvent) => { + setSearchQuery(e.target.value); + }, []); + + const handleFeedDropdownToggle = useCallback(() => { + setShowFeedDropdown((prev) => !prev); + }, []); + + const handleTimeDropdownToggle = useCallback(() => { + setShowTimeDropdown((prev) => !prev); + }, []); + + const handleFeedDropdownClose = useCallback(() => { + setShowFeedDropdown(false); + }, []); + + const handleTimeDropdownClose = useCallback(() => { + setShowTimeDropdown(false); + }, []); + + const filteredLeaderboard = useMemo(() => { + return leaderboard?.filter((item) => { + const searchTerm = debouncedSearchQuery?.toLowerCase(); + const feedFilter = + search.feed === "all feeds" + ? true + : item.feedSubmissions?.some((feed) => feed.feedId === search.feed); + + const matchesSearch = + !searchTerm || + item.curatorUsername?.toLowerCase().includes(searchTerm) || + item.feedSubmissions?.some((feed) => + feed.feedId?.toLowerCase().includes(searchTerm), + ); + + return feedFilter && matchesSearch; + }); + }, [leaderboard, debouncedSearchQuery, search.feed]); + + const filteredLeaderboardWithRanks = useMemo(() => { + return filteredLeaderboard?.map((item) => { + const originalIndex = leaderboard?.findIndex( + (entry) => entry.curatorId === item.curatorId, + ); + return { + ...item, + originalRank: originalIndex !== undefined ? originalIndex + 1 : 0, + }; + }); + }, [filteredLeaderboard, leaderboard]); + + const columns = useMemo(() => { + return createLeaderboardColumns(expandedRows, toggleRow); + }, [expandedRows, toggleRow]); + + const table = useReactTable({ + data: filteredLeaderboardWithRanks || [], + columns, + state: { + sorting, + }, + onSortingChange: setSorting, + getCoreRowModel: getCoreRowModel(), + getSortedRowModel: getSortedRowModel(), + }); + + return { + // State + searchQuery, + showFeedDropdown, + showTimeDropdown, + feeds, + timeOptions, + + // Handlers + handleSearch, + handleFeedDropdownToggle, + handleTimeDropdownToggle, + handleFeedDropdownClose, + handleTimeDropdownClose, + + // Refs + feedDropdownRef, + timeDropdownRef, + + // Table + table, + hasData: Boolean(leaderboard && leaderboard.length > 0), + }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4490405a..a76c87be 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -128,13 +128,13 @@ importers: devDependencies: '@module-federation/node': specifier: ^2.6.30 - version: 2.7.7(@rspack/core@1.2.8(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)) + version: 2.7.7(@rspack/core@1.2.8(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(webpack@5.99.9) '@rspack/binding': specifier: 1.2.8 version: 1.2.8 '@rspack/cli': specifier: 1.2.8 - version: 1.2.8(@rspack/core@1.2.8(@swc/helpers@0.5.17))(@types/express@4.17.23)(webpack@5.99.9(esbuild@0.25.5)) + version: 1.2.8(@rspack/core@1.2.8(@swc/helpers@0.5.17))(@types/express@4.17.23)(webpack@5.99.9) '@rspack/core': specifier: 1.2.8 version: 1.2.8(@swc/helpers@0.5.17) @@ -219,6 +219,9 @@ importers: '@tanstack/react-router': specifier: 1.97.0 version: 1.97.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-table': + specifier: ^8.21.3 + version: 8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) autoprefixer: specifier: ^10.4.20 version: 10.4.21(postcss@8.5.5) @@ -2152,6 +2155,13 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/react-table@8.21.3': + resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + '@tanstack/router-core@1.121.27': resolution: {integrity: sha512-6lCQ3p7KhJ8Qy33TPRM6wIkQ1XKaikD5qqx3K2fPr3YtyDNefKQValbSAkb2CBB+hlDodfHNyxemE9alnQr55A==} engines: {node: '>=12'} @@ -2190,6 +2200,10 @@ packages: '@tanstack/store@0.7.1': resolution: {integrity: sha512-PjUQKXEXhLYj2X5/6c1Xn/0/qKY0IVFxTJweopRfF26xfjVyb14yALydJrHupDh3/d+1WKmfEgZPBVCmDkzzwg==} + '@tanstack/table-core@8.21.3': + resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} + engines: {node: '>=12'} + '@tanstack/virtual-file-routes@1.121.21': resolution: {integrity: sha512-3nuYsTyaq6ZN7jRZ9z6Gj3GXZqBOqOT0yzd/WZ33ZFfv4yVNIvsa5Lw+M1j3sgyEAxKMqGu/FaNi7FCjr3yOdw==} engines: {node: '>=12'} @@ -2456,6 +2470,7 @@ packages: agent-twitter-client@0.0.16: resolution: {integrity: sha512-Clgb/N2LXoGMlId6GDUaaR05eJ0PqSifM6wikl/FiQ2+3+6I2ZhZB7KRulc8R4xvYFe6h0wNWe6FZiF48r124w==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} @@ -5955,7 +5970,7 @@ snapshots: - supports-color - utf-8-validate - '@module-federation/enhanced@0.15.0(@rspack/core@1.2.8(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5))': + '@module-federation/enhanced@0.15.0(@rspack/core@1.2.8(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(webpack@5.99.9)': dependencies: '@module-federation/bridge-react-webpack-plugin': 0.15.0 '@module-federation/cli': 0.15.0(typescript@5.8.3) @@ -5973,7 +5988,7 @@ snapshots: upath: 2.0.1 optionalDependencies: typescript: 5.8.3 - webpack: 5.99.9(esbuild@0.25.5) + webpack: 5.99.9 transitivePeerDependencies: - '@rspack/core' - bufferutil @@ -6014,15 +6029,15 @@ snapshots: - utf-8-validate - vue-tsc - '@module-federation/node@2.7.7(@rspack/core@1.2.8(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5))': + '@module-federation/node@2.7.7(@rspack/core@1.2.8(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(webpack@5.99.9)': dependencies: - '@module-federation/enhanced': 0.15.0(@rspack/core@1.2.8(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)) + '@module-federation/enhanced': 0.15.0(@rspack/core@1.2.8(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)(webpack@5.99.9) '@module-federation/runtime': 0.15.0 '@module-federation/sdk': 0.15.0 btoa: 1.2.1 encoding: 0.1.13 node-fetch: 2.7.0(encoding@0.1.13) - webpack: 5.99.9(esbuild@0.25.5) + webpack: 5.99.9 optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -6888,11 +6903,11 @@ snapshots: '@rspack/binding-win32-ia32-msvc': 1.2.8 '@rspack/binding-win32-x64-msvc': 1.2.8 - '@rspack/cli@1.2.8(@rspack/core@1.2.8(@swc/helpers@0.5.17))(@types/express@4.17.23)(webpack@5.99.9(esbuild@0.25.5))': + '@rspack/cli@1.2.8(@rspack/core@1.2.8(@swc/helpers@0.5.17))(@types/express@4.17.23)(webpack@5.99.9)': dependencies: '@discoveryjs/json-ext': 0.5.7 '@rspack/core': 1.2.8(@swc/helpers@0.5.17) - '@rspack/dev-server': 1.0.10(@rspack/core@1.2.8(@swc/helpers@0.5.17))(@types/express@4.17.23)(webpack@5.99.9(esbuild@0.25.5)) + '@rspack/dev-server': 1.0.10(@rspack/core@1.2.8(@swc/helpers@0.5.17))(@types/express@4.17.23)(webpack@5.99.9) colorette: 2.0.20 exit-hook: 4.0.0 interpret: 3.1.1 @@ -6926,7 +6941,7 @@ snapshots: optionalDependencies: '@swc/helpers': 0.5.17 - '@rspack/dev-server@1.0.10(@rspack/core@1.2.8(@swc/helpers@0.5.17))(@types/express@4.17.23)(webpack@5.99.9(esbuild@0.25.5))': + '@rspack/dev-server@1.0.10(@rspack/core@1.2.8(@swc/helpers@0.5.17))(@types/express@4.17.23)(webpack@5.99.9)': dependencies: '@rspack/core': 1.2.8(@swc/helpers@0.5.17) chokidar: 3.6.0 @@ -6935,8 +6950,8 @@ snapshots: http-proxy-middleware: 2.0.9(@types/express@4.17.23) mime-types: 2.1.35 p-retry: 4.6.2 - webpack-dev-middleware: 7.4.2(webpack@5.99.9(esbuild@0.25.5)) - webpack-dev-server: 5.0.4(webpack@5.99.9(esbuild@0.25.5)) + webpack-dev-middleware: 7.4.2(webpack@5.99.9) + webpack-dev-server: 5.0.4(webpack@5.99.9) ws: 8.18.2 transitivePeerDependencies: - '@types/express' @@ -7014,6 +7029,12 @@ snapshots: react-dom: 18.3.1(react@18.3.1) use-sync-external-store: 1.5.0(react@18.3.1) + '@tanstack/react-table@8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/table-core': 8.21.3 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + '@tanstack/router-core@1.121.27': dependencies: '@tanstack/history': 1.121.21 @@ -7083,6 +7104,8 @@ snapshots: '@tanstack/store@0.7.1': {} + '@tanstack/table-core@8.21.3': {} + '@tanstack/virtual-file-routes@1.121.21': {} '@types/async-retry@1.4.9': @@ -9820,17 +9843,6 @@ snapshots: tapable@2.2.2: {} - terser-webpack-plugin@5.3.14(esbuild@0.25.5)(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - jest-worker: 27.5.1 - schema-utils: 4.3.2 - serialize-javascript: 6.0.2 - terser: 5.42.0 - webpack: 5.99.9(esbuild@0.25.5) - optionalDependencies: - esbuild: 0.25.5 - terser-webpack-plugin@5.3.14(webpack@5.99.9): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -9839,7 +9851,6 @@ snapshots: serialize-javascript: 6.0.2 terser: 5.42.0 webpack: 5.99.9 - optional: true terser@5.42.0: dependencies: @@ -10097,7 +10108,7 @@ snapshots: - bufferutil - utf-8-validate - webpack-dev-middleware@7.4.2(webpack@5.99.9(esbuild@0.25.5)): + webpack-dev-middleware@7.4.2(webpack@5.99.9): dependencies: colorette: 2.0.20 memfs: 4.17.2 @@ -10106,9 +10117,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.2 optionalDependencies: - webpack: 5.99.9(esbuild@0.25.5) + webpack: 5.99.9 - webpack-dev-server@5.0.4(webpack@5.99.9(esbuild@0.25.5)): + webpack-dev-server@5.0.4(webpack@5.99.9): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -10138,10 +10149,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.99.9(esbuild@0.25.5)) + webpack-dev-middleware: 7.4.2(webpack@5.99.9) ws: 8.18.2 optionalDependencies: - webpack: 5.99.9(esbuild@0.25.5) + webpack: 5.99.9 transitivePeerDependencies: - bufferutil - debug @@ -10182,38 +10193,6 @@ snapshots: - '@swc/core' - esbuild - uglify-js - optional: true - - webpack@5.99.9(esbuild@0.25.5): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - browserslist: 4.25.0 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.1 - es-module-lexer: 1.7.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.2 - tapable: 2.2.2 - terser-webpack-plugin: 5.3.14(esbuild@0.25.5)(webpack@5.99.9(esbuild@0.25.5)) - watchpack: 2.4.4 - webpack-sources: 3.3.2 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js websocket-driver@0.7.4: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 3ff5faaa..e9cea57a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,7 @@ packages: - - "apps/*" - - "packages/*" + - apps/* + - packages/* +onlyBuiltDependencies: + - core-js + - esbuild + - secp256k1