+
List for sale
- Type of sale
+ Type of sale
diff --git a/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/components/token-activity.tsx b/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/components/token-activity.tsx
index 370457a2..69a66711 100644
--- a/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/components/token-activity.tsx
+++ b/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/components/token-activity.tsx
@@ -1,115 +1,88 @@
-import {
- ArrowLeftRight,
- List,
- ListX,
- ShoppingCart,
- Tag,
- X,
-} from "lucide-react";
+"use client";
+
+import { useMemo, useRef } from "react";
+import { useInfiniteQuery } from "@tanstack/react-query";
import type { PropsWithClassName } from "@ark-market/ui";
import { cn } from "@ark-market/ui";
-import { PriceTag } from "@ark-market/ui/price-tag";
-import {
- Table,
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
-} from "@ark-market/ui/table";
-const activityTypeToItem = new Map([
- ["sale", { icon:
, title: "Sale" }],
- ["transfer", { icon:
, title: "Transfer" }],
- ["list", { icon:
, title: "List" }],
- ["offer", { icon:
, title: "Offer" }],
- ["cancel_offer", { icon:
, title: "Cancel Offer" }],
- ["delist", { icon:
, title: "Delist" }],
-]);
+import type { TokenActivityApiResponse } from "../queries/getTokenData";
+import useInfiniteWindowScroll from "~/hooks/useInfiniteWindowScroll";
+import { getTokenActivity } from "../queries/getTokenData";
+import DesktopTokenActivity from "./desktop-token-activity";
+import MobileTokenActivity from "./mobile-token-activity";
+
+interface TokenActivityProps {
+ contractAddress: string;
+ tokenId: string;
+}
+
+export default function TokenActivity({
+ className,
+ contractAddress,
+ tokenId,
+}: PropsWithClassName
) {
+ const tableContainerRef = useRef(null);
+ const {
+ data: infiniteData,
+ fetchNextPage,
+ hasNextPage,
+ isFetchingNextPage,
+ } = useInfiniteQuery({
+ queryKey: ["tokenActivity", contractAddress, tokenId],
+ refetchInterval: 10_000,
+ // getNextPageParam: (lastPage) => lastPage.next_page,
+ getNextPageParam: (lastPage?: TokenActivityApiResponse) =>
+ lastPage?.next_page,
+ initialPageParam: undefined,
+ queryFn: ({ pageParam }) =>
+ getTokenActivity({ contractAddress, tokenId, page: pageParam }),
+ });
+
+ const totalCount = infiniteData?.pages[0]?.count ?? 0;
+ const tokenActivity = useMemo(
+ () => infiniteData?.pages.flatMap((page) => page?.data ?? []) ?? [],
+ [infiniteData],
+ );
+ console.log(tokenActivity);
+
+ useInfiniteWindowScroll({
+ fetchNextPage,
+ hasNextPage,
+ isFetchingNextPage,
+ });
-const activityData = [
- {
- type: "transfer",
- from: "0x123",
- to: "0x456",
- },
- {
- type: "list",
- price: 1180000000000000000n,
- from: "0x123",
- },
- {
- type: "offer",
- price: 1840000000000000000n,
- from: "0x123",
- to: "0x456",
- },
- {
- type: "cancel_offer",
- price: 1540000000000000000n,
- from: "0x123",
- to: "0x456",
- },
- {
- type: "delist",
- price: 3240000000000000000n,
- from: "0x123",
- },
- {
- type: "sale",
- price: 1140000000000000000n,
- from: "0x123",
- to: "0x456",
- },
-];
+ // const rowVirtualizer = useWindowVirtualizer({
+ // // Approximate initial rect for SSR
+ // initialRect: { height: 1080, width: 1920 },
+ // count: tokenActivity.length,
+ // estimateSize: () => 75, // Estimation of row height for accurate scrollbar dragging
+ // // Measure dynamic row height, except in firefox because it measures table border height incorrectly
+ // measureElement:
+ // typeof window !== "undefined" && !navigator.userAgent.includes("Firefox")
+ // ? (element) => element.getBoundingClientRect().height
+ // : undefined,
+ // overscan: 5,
+ // scrollMargin: tableContainer.current?.offsetTop ?? 0,
+ // });
-export default function TokenActivity({ className }: PropsWithClassName) {
return (
-
+
Activity
- {activityData.length}
+ {totalCount}
-
-
-
- Event
- Price
- From
- To
- Date
-
-
-
- {activityData.map((activity, index) => {
- const activityItem = activityTypeToItem.get(activity.type);
- return (
-
-
-
- {activityItem?.icon}
-
{activityItem?.title}
-
-
-
- {activity.price !== undefined ? (
-
- ) : (
- "_"
- )}
-
- {activity.from}
- {activity.to ?? "_"}
- 8min ago
-
- );
- })}
-
-
+
);
}
diff --git a/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/components/token-summary.tsx b/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/components/token-summary.tsx
index 6760d24b..c3ba58ee 100644
--- a/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/components/token-summary.tsx
+++ b/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/components/token-summary.tsx
@@ -2,7 +2,7 @@ import Link from "next/link";
import { RefreshCw, Share2 } from "lucide-react";
import type { PropsWithClassName } from "@ark-market/ui";
-import { cn, ellipsableStyles } from "@ark-market/ui";
+import { cn, ellipsableStyles, focusableStyles } from "@ark-market/ui";
import VerifiedIcon from "@ark-market/ui/icons/verified-icon";
import type { TokenInfosApiResponse } from "../queries/getTokenData";
@@ -43,7 +43,10 @@ export default function TokenSummary({
/>
-
+
{tokenInfos.collection_name}
diff --git a/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/page.tsx b/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/page.tsx
index 50114b19..e90f8e3d 100644
--- a/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/page.tsx
+++ b/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/page.tsx
@@ -5,7 +5,6 @@ import {
getCollectionToken,
getOrderbookCollectionToken,
} from "~/app/assets/[contract_address]/[token_id]/data";
-import MobileTokenActivity from "./components/mobile-token-activity";
import TokenAbout from "./components/token-about";
import TokenActions from "./components/token-actions";
import TokenActivity from "./components/token-activity";
@@ -93,8 +92,11 @@ export default async function TokenPage({
/>
-
-
+
);
}
diff --git a/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/queries/getTokenData.ts b/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/queries/getTokenData.ts
index 2cb0b0c7..09040ce3 100644
--- a/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/queries/getTokenData.ts
+++ b/apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/queries/getTokenData.ts
@@ -79,3 +79,50 @@ export async function getTokenOffers({
return (await response.json()) as Promise
;
}
+
+export type TokenActivityType =
+ | "LISTING"
+ | "OFFER"
+ | "CANCELLED"
+ | "FULFILL"
+ | "TRANSFER"
+ | "EXECUTED"
+ | "MINT";
+export interface TokenActivity {
+ activity_type: TokenActivityType;
+ from: string | null;
+ price: string | null;
+ time_stamp: number;
+ to: string | null;
+ transaction_hash: string | null;
+}
+export interface TokenActivityApiResponse {
+ data: TokenActivity[];
+ count: number;
+ next_page: number;
+}
+interface GetTokenActivityParams {
+ contractAddress: string;
+ page?: number;
+ tokenId: string;
+}
+export async function getTokenActivity({
+ contractAddress,
+ page,
+ tokenId,
+}: GetTokenActivityParams) {
+ const queryParams = [`items_per_page=${30}`];
+ if (page !== undefined) {
+ queryParams.push(`page=${page}`);
+ }
+
+ const url = `${env.NEXT_PUBLIC_MARKETPLACE_API_URL}/tokens/${contractAddress}/0x534e5f4d41494e/${tokenId}/activity?${queryParams.join("&")}`;
+
+ const response = await fetch(url);
+ if (!response.ok) {
+ console.error(url, response.status);
+ return undefined;
+ }
+
+ return (await response.json()) as Promise;
+}
diff --git a/apps/arkmarket/src/app/wallet/[walletAddress]/components/portfolio-items-data-list-view.tsx b/apps/arkmarket/src/app/wallet/[walletAddress]/components/portfolio-items-data-list-view.tsx
index 0acb941d..36157309 100644
--- a/apps/arkmarket/src/app/wallet/[walletAddress]/components/portfolio-items-data-list-view.tsx
+++ b/apps/arkmarket/src/app/wallet/[walletAddress]/components/portfolio-items-data-list-view.tsx
@@ -77,13 +77,13 @@ export default function PortfolioItemsDataListView({
return (
rowVirtualizer.measureElement(node)} // Measure dynamic row height
className={cn(
"group absolute grid h-[4.6875rem] w-full items-center",
gridTemplateColumnValue,
)}
+ data-index={virtualRow.index} // Needed for dynamic row height measurement
+ key={`${token.contract}-${token.token_id}`}
+ ref={(node) => rowVirtualizer.measureElement(node)} // Measure dynamic row height
style={{
transform: `translateY(${virtualRow.start}px)`,
}}
diff --git a/apps/arkmarket/src/components/footer.tsx b/apps/arkmarket/src/components/footer.tsx
index b1d5cb3e..2168417d 100644
--- a/apps/arkmarket/src/components/footer.tsx
+++ b/apps/arkmarket/src/components/footer.tsx
@@ -14,7 +14,11 @@ import { Icons } from "./icons";
export default function Footer() {
const pathname = usePathname();
- if (pathname.includes("/wallet/") || pathname.includes("/collection/")) {
+ if (
+ pathname.includes("/wallet/") ||
+ pathname.includes("/collection/") ||
+ pathname.includes("/token/")
+ ) {
return null;
}
diff --git a/packages/ui/src/form.tsx b/packages/ui/src/form.tsx
index 72a45c55..e44cd0c0 100644
--- a/packages/ui/src/form.tsx
+++ b/packages/ui/src/form.tsx
@@ -74,7 +74,7 @@ const FormItem = React.forwardRef<
return (
-
+
);
});
diff --git a/packages/ui/src/label.tsx b/packages/ui/src/label.tsx
index bbcf21b9..11940010 100644
--- a/packages/ui/src/label.tsx
+++ b/packages/ui/src/label.tsx
@@ -8,7 +8,7 @@ import { cva } from "class-variance-authority";
import { cn } from "@ark-market/ui";
const labelVariants = cva(
- "font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
+ "font-semibold leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
);
const Label = React.forwardRef<