Skip to content

Commit

Permalink
Merge pull request #44 from ArkProjectNFTs/yohan/activity
Browse files Browse the repository at this point in the history
feat: token activity with infinite scroll
  • Loading branch information
kwiss authored Jul 8, 2024
2 parents 9abb78e + 1792d59 commit 6d24d9f
Show file tree
Hide file tree
Showing 13 changed files with 315 additions and 215 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import {
ArrowLeftRight,
CircleDot,
Gavel,
List,
ListX,
Meh,
ShoppingCart,
Tag,
X,
} from "lucide-react";

import type { PropsWithClassName } from "@ark-market/ui";
import { shortAddress, timeSince } from "@ark-market/ui";
import { PriceTag } from "@ark-market/ui/price-tag";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@ark-market/ui/table";

import type { TokenActivity } from "../queries/getTokenData";

export const activityTypeToItem = new Map([
["FULFILL", { icon: <ShoppingCart size={24} />, title: "Sale in progress" }],
["EXECUTED", { icon: <ShoppingCart size={24} />, title: "Sale" }],
["SALE", { icon: <ShoppingCart size={24} />, title: "Sale" }],
["TRANSFER", { icon: <ArrowLeftRight size={24} />, title: "Transfer" }],
["LISTING", { icon: <List size={24} />, title: "List" }],
["OFFER", { icon: <Tag size={24} />, title: "Offer" }],
["CANCELLED", { icon: <X size={24} />, title: "Cancel Offer" }],
["MINT", { icon: <CircleDot size={24} />, title: "Mint" }],
["AUCTION", { icon: <Gavel size={24} />, title: "Put in auction" }],
["DELISTING", { icon: <ListX size={24} />, title: "Delist" }],
]);

interface DesktopTokenActivityProps {
tokenActivity: TokenActivity[];
}

export default function DesktopTokenActivity({
className,
tokenActivity,
}: PropsWithClassName<DesktopTokenActivityProps>) {
return (
<Table className={className}>
<TableHeader>
<TableRow className="hover:bg-background">
<TableHead className="pl-5">Event</TableHead>
<TableHead>Price</TableHead>
<TableHead>From</TableHead>
<TableHead>To</TableHead>
<TableHead>Date</TableHead>
</TableRow>
</TableHeader>
{tokenActivity.length === 0 ? (
<TableBody className="table-caption">
<div className="flex flex-col items-center gap-3 pt-10 text-muted-foreground">
<Meh size={42} />
<p className="text-xl font-semibold">No activity yet!</p>
</div>
</TableBody>
) : (
<TableBody className="text-sm font-semibold">
{tokenActivity.map((activity, index) => {
const activityItem = activityTypeToItem.get(activity.activity_type);

return (
<TableRow className="group h-[4.6875rem]" key={index}>
<TableCell className="pl-5 transition-colors group-hover:text-muted-foreground">
<div className="flex items-center gap-4 whitespace-nowrap">
{activityItem?.icon}
<p>{activityItem?.title}</p>
</div>
</TableCell>
<TableCell>
{activity.price !== null ? (
<PriceTag price={activity.price} />
) : (
"_"
)}
</TableCell>
<TableCell>
{activity.from ? shortAddress(activity.from) : "_"}
</TableCell>
<TableCell>
{activity.to ? shortAddress(activity.to) : "_"}
</TableCell>
<TableCell>{timeSince(activity.time_stamp)}</TableCell>
</TableRow>
);
})}
</TableBody>
)}
</Table>
);
}
Original file line number Diff line number Diff line change
@@ -1,109 +1,67 @@
import { Fragment } from "react";
import {
ArrowLeftRight,
List,
ListX,
ShoppingCart,
Tag,
X,
} from "lucide-react";
import { Meh } from "lucide-react";

import type { PropsWithClassName } from "@ark-market/ui";
import { cn } from "@ark-market/ui";
import { shortAddress, timeSince } from "@ark-market/ui";
import { PriceTag } from "@ark-market/ui/price-tag";
import { Separator } from "@ark-market/ui/separator";

const activityTypeToItem = new Map([
["sale", { icon: <ShoppingCart size={20} />, title: "Sale" }],
["transfer", { icon: <ArrowLeftRight size={20} />, title: "Transfer" }],
["list", { icon: <List size={20} />, title: "List" }],
["offer", { icon: <Tag size={20} />, title: "Offer" }],
["cancel_offer", { icon: <X size={20} />, title: "Cancel Offer" }],
["delist", { icon: <ListX size={20} />, title: "Delist" }],
]);
import type { TokenActivity } from "../queries/getTokenData";
import { activityTypeToItem } from "./desktop-token-activity";

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",
},
];
interface MobileTokenActivityProps {
tokenActivity: TokenActivity[];
}

export default function MobileTokenActivity({ className }: PropsWithClassName) {
export default function MobileTokenActivity({
className,
tokenActivity,
}: PropsWithClassName<MobileTokenActivityProps>) {
return (
<div className={cn("", className)}>
<div className="flex items-center gap-4">
<h2 className="text-2xl font-semibold">Activity</h2>
<div className="flex h-6 items-center rounded-full bg-secondary px-3 text-sm font-medium text-secondary-foreground">
{activityData.length}
</div>
</div>
<div className={className}>
<p className="text-sm font-semibold text-muted-foreground">Event</p>
<Separator className="my-4" />

<div className="mt-6">
<p className="text-sm font-semibold text-muted-foreground">Event</p>
<Separator className="my-4" />
{tokenActivity.length === 0 && (
<div className="flex flex-col items-center gap-3 py-10 text-muted-foreground">
<Meh size={42} />
<p className="text-xl font-semibold">No activity yet!</p>
</div>
)}

{activityData.map((activity, index) => {
const activityItem = activityTypeToItem.get(activity.type);
{tokenActivity.map((activity, index) => {
const activityItem = activityTypeToItem.get(activity.activity_type);

return (
<Fragment key={index}>
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2.5">
{activityItem?.icon}
<p>{activityItem?.title}</p>
</div>
{activity.price !== undefined ? (
<PriceTag price={activity.price} className="h-7 text-xs" />
) : (
"_"
)}
</div>
<div className="flex items-center justify-between text-sm font-semibold">
<p>
by{" "}
<span className="text-muted-foreground">
{activity.from}{" "}
</span>
</p>
<p className="text-xs text-muted-foreground">8min ago</p>
return (
<Fragment key={index}>
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2.5">
{activityItem?.icon}
<p>{activityItem?.title}</p>
</div>
{activity.price !== null ? (
<PriceTag price={activity.price} className="h-7 text-xs" />
) : (
"_"
)}
</div>
<div className="flex items-center justify-between text-sm font-semibold">
<p>
by{" "}
<span className="text-muted-foreground">
{activity.from ? shortAddress(activity.from) : "_"}
</span>
</p>
<p className="text-xs text-muted-foreground">
{timeSince(activity.time_stamp)}
</p>
</div>
<Separator className="my-4" />
</Fragment>
);
})}
</div>
</div>
<Separator className="my-4" />
</Fragment>
);
})}
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useMemo, useState } from "react";
import { ChevronDown, ChevronUp } from "lucide-react";

import type { PropsWithClassName } from "@ark-market/ui";
import { cn } from "@ark-market/ui";
import { cn, ellipsableStyles } from "@ark-market/ui";
import { Button } from "@ark-market/ui/button";
import {
Collapsible,
Expand Down Expand Up @@ -100,9 +100,11 @@ export default function TokenAbout({
{collectionShortenedAddress}
</p>
</div>
<div className="flex items-center justify-between">
<p className="font-medium">Token ID</p>
<p className="text-muted-foreground">{tokenId}</p>
<div className="flex items-center justify-between gap-4">
<p className="whitespace-nowrap font-medium">Token ID</p>
<p className={cn("text-muted-foreground", ellipsableStyles)}>
{tokenId}
</p>
</div>
<div className="flex items-center justify-between">
<p className="font-medium">Token Standard</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ export function TokenActionsCreateListing({
</DialogTrigger>
<DialogContent>
<DialogHeader className="items-center"></DialogHeader>
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-8">
<div className="text-center text-xl font-semibold">List for sale</div>
<TokenActionsTokenOverview
collection={collection}
Expand All @@ -205,7 +205,7 @@ export function TokenActionsCreateListing({
className="flex flex-col space-y-4"
>
<FormItem className="">
<FormLabel>Type of sale</FormLabel>
<FormLabel className="text-lg">Type of sale</FormLabel>
<div className="flex gap-6">
<Button
type="button"
Expand Down Expand Up @@ -233,7 +233,9 @@ export function TokenActionsCreateListing({
name="startAmount"
render={({ field }) => (
<FormItem>
<FormLabel>Set starting price</FormLabel>
<FormLabel className="text-lg">
Set {isAuction && "starting"} price
</FormLabel>
<Button
type="button"
className="w-full"
Expand All @@ -243,16 +245,23 @@ export function TokenActionsCreateListing({
field.onChange("0.5");
}}
>
Choose floor price 0.5 ETH
<p>
Choose floor price of{" "}
<span className="font-bold">0.5 ETH</span>
</p>
</Button>
<FormControl>
<NumericalInput
// {...field}
defaultValue="0.1"
value={field.value}
onChange={field.onChange}
placeholder="Price"
/>
</FormControl>
<p className="!mt-1 ml-3 text-sm text-muted-foreground">
$---
</p>
{formattedStartAmount !== "-" && <FormMessage />}
</FormItem>
)}
Expand All @@ -263,7 +272,9 @@ export function TokenActionsCreateListing({
name="endAmount"
render={({ field }) => (
<FormItem>
<FormLabel>Set reserve price</FormLabel>
<FormLabel className="text-lg">
Set reserve price
</FormLabel>
<FormControl>
<NumericalInput
value={field.value}
Expand All @@ -280,7 +291,7 @@ export function TokenActionsCreateListing({
name="duration"
render={({ field }) => (
<FormItem>
<FormLabel>Set expiration</FormLabel>
<FormLabel className="text-lg">Set expiration</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value.toString()}
Expand All @@ -304,7 +315,7 @@ export function TokenActionsCreateListing({
/>
<Button
type="submit"
className="mx-auto w-full px-10 lg:w-auto"
className="mx-auto !mt-8 w-full px-10 lg:w-auto"
disabled={isDisabled}
size="xl"
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BadgeCheck } from "lucide-react";
import VerifiedIcon from "@ark-market/ui/icons/verified-icon";

import type { Collection, Token } from "~/types";
import TokenMedia from "~/app/assets/[contract_address]/[token_id]/components/token-media";
Expand All @@ -25,7 +25,7 @@ export default function TokenActionsTokenOverview({
<div className="text-lg font-semibold text-muted-foreground">
{collection.name || "Unknown"}
</div>
<BadgeCheck className="size-4 text-muted-foreground" />
<VerifiedIcon className="size-6 text-background" />
</div>
</div>
<div className="grow" />
Expand Down
Loading

0 comments on commit 6d24d9f

Please sign in to comment.