Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions app/[alias]/(dashboard)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { getMembersAction } from '@/app/[alias]/(dashboard)/members/action';
import { getTransfersOfTokenAction } from '@/app/[alias]/(dashboard)/transfers/actions';
import { getAuthUserAction } from '@/app/_actions/user-actions';
import {
MetricCard,
MetricCardSkeleton
} from '@/components/custom/metric-card';
import { getServiceRoleClient as getChainDbServiceRoleClient } from '@/services/chain-db';
import { getMembers } from '@/services/chain-db/members';
import { getTransfersOfToken } from '@/services/chain-db/transfers';
import { getServiceRoleClient } from '@/services/top-db';
import { getCommunityByAlias } from '@/services/top-db/community';
import { SupabaseClient } from '@supabase/supabase-js';
Expand Down Expand Up @@ -96,14 +97,19 @@ export default async function Page(props: {

async function getMembersOverview({ alias, client }: { alias: string, client: SupabaseClient }) {

const { data, error } = await getCommunityByAlias(client, alias);
const { data: communityData, error: communityError } = await getCommunityByAlias(client, alias);

if (error || !data) {
if (communityError || !communityData) {
throw new Error('Failed to get community by alias');
}

const { count } = await getMembersAction({
config: data.json,
const { chain_id: chainId, address: profileContract } = communityData.json.community.profile;
const supabase = getChainDbServiceRoleClient(chainId);


const { count } = await getMembers({
client: supabase,
profileContract,
query: '',
page: 1,
showAllMembers: true
Expand All @@ -119,17 +125,24 @@ async function getMembersOverview({ alias, client }: { alias: string, client: Su
}

async function getTransactionsOverview({ alias, client }: { alias: string, client: SupabaseClient }) {
const { data, error } = await getCommunityByAlias(client, alias);
const { data: communityData, error: communityError } = await getCommunityByAlias(client, alias);

if (error || !data) {
if (communityError || !communityData) {
throw new Error('Failed to get community by alias');
}

const { count } = await getTransfersOfTokenAction({
config: data.json,
const { chain_id: chainId, address: tokenAddress } =
communityData.json.community.primary_token;
const supabase = getChainDbServiceRoleClient(chainId);


const { count } = await getTransfersOfToken({
client: supabase,
token: tokenAddress,
query: '',
page: 1
});
page: 1,
})


return (
<MetricCard
Expand Down
228 changes: 114 additions & 114 deletions app/[alias]/(dashboard)/transfers/_table/columns.tsx
Original file line number Diff line number Diff line change
@@ -1,140 +1,140 @@
'use client';

import { ColumnDef } from '@tanstack/react-table';
import { CommunityConfig } from '@citizenwallet/sdk';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { TransferWithMembersT } from '@/services/chain-db/transfers';
import { formatAddress } from '@/lib/utils';
import { CommunityLogo } from '@/components/icons';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Skeleton } from '@/components/ui/skeleton';
import { formatAddress } from '@/lib/utils';
import { TransferWithMembersResponseT, TransferWithMembersT } from '@/services/chain-db/transfers';
import { CommunityConfig } from '@citizenwallet/sdk';
import { ColumnDef } from '@tanstack/react-table';

export const createColumns = (
communityConfig: CommunityConfig
): ColumnDef<TransferWithMembersT>[] => [
{
header: 'ID',
accessorKey: 'id',
cell: ({ row }) => {
const hash = row.original.hash;
const hashFormatted = formatAddress(hash);
): ColumnDef<TransferWithMembersResponseT>[] => [
{
header: 'ID',
accessorKey: 'id',
cell: ({ row }) => {
const hash = row.original.hash;
const hashFormatted = formatAddress(hash);

return <span className="text-xs font-mono">{hashFormatted}</span>;
return <span className="text-xs font-mono">{hashFormatted}</span>;
},
size: 120 // Fixed width for hash
},
size: 120 // Fixed width for hash
},
{
header: 'From',
accessorKey: 'from_member',
cell: ({ row }) => {
const { image, username, name, account } = row.original.from_member;
{
header: 'From',
accessorKey: 'from_member',
cell: ({ row }) => {
const { image, username, name, account } = row.original.from_member;

const isAnonymous = username?.includes('anonymous');
const isZeroAddress =
account === '0x0000000000000000000000000000000000000000';
const isAnonymous = username?.includes('anonymous');
const isZeroAddress =
account === '0x0000000000000000000000000000000000000000';

return (
<div className="flex items-center gap-2 min-w-[200px]">
<Avatar className="h-8 w-8 flex-shrink-0">
<AvatarImage src={image} alt={username} />
<AvatarFallback>{username.slice(0, 2)}</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<span className="text-xs text-muted-foreground">
{isZeroAddress
? `@${communityConfig.primaryToken.symbol}`
: `@${username}`}
</span>
{isAnonymous ? (
<span className="text-xs font-mono">
return (
<div className="flex items-center gap-2 min-w-[200px]">
<Avatar className="h-8 w-8 flex-shrink-0">
<AvatarImage src={image} alt={username} />
<AvatarFallback>{username.slice(0, 2)}</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<span className="text-xs text-muted-foreground">
{isZeroAddress
? communityConfig.community.name
: formatAddress(account)}
? `@${communityConfig.primaryToken.symbol}`
: `@${username}`}
</span>
) : (
<span className="text-xs font-mono">{name}</span>
)}
{isAnonymous ? (
<span className="text-xs font-mono">
{isZeroAddress
? communityConfig.community.name
: formatAddress(account)}
</span>
) : (
<span className="text-xs font-mono">{name}</span>
)}
</div>
</div>
</div>
);
}
},
{
header: 'To',
accessorKey: 'to_member',
cell: ({ row }) => {
const { image, username, name, account } = row.original.to_member;
);
}
},
{
header: 'To',
accessorKey: 'to_member',
cell: ({ row }) => {
const { image, username, name, account } = row.original.to_member;

const isAnonymous = username?.includes('anonymous');
const isZeroAddress =
account === '0x0000000000000000000000000000000000000000';
const isAnonymous = username?.includes('anonymous');
const isZeroAddress =
account === '0x0000000000000000000000000000000000000000';

return (
<div className="flex items-center gap-2 min-w-[200px]">
<Avatar className="h-8 w-8 flex-shrink-0">
<AvatarImage src={image} alt={username} />
<AvatarFallback>{username.slice(0, 2)}</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<span className="text-xs text-muted-foreground">
{isZeroAddress
? `@${communityConfig.primaryToken.symbol}`
: `@${username}`}
</span>
{isAnonymous ? (
<span className="text-xs font-mono">
return (
<div className="flex items-center gap-2 min-w-[200px]">
<Avatar className="h-8 w-8 flex-shrink-0">
<AvatarImage src={image} alt={username} />
<AvatarFallback>{username.slice(0, 2)}</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<span className="text-xs text-muted-foreground">
{isZeroAddress
? communityConfig.community.name
: formatAddress(account)}
? `@${communityConfig.primaryToken.symbol}`
: `@${username}`}
</span>
) : (
<span className="text-xs font-mono">{name}</span>
)}
{isAnonymous ? (
<span className="text-xs font-mono">
{isZeroAddress
? communityConfig.community.name
: formatAddress(account)}
</span>
) : (
<span className="text-xs font-mono">{name}</span>
)}
</div>
</div>
</div>
);
}
},
{
header: 'Value',
accessorKey: 'value',
cell: ({ row }) => {
const value = row.original.value;
);
}
},
{
header: 'Value',
accessorKey: 'value',
cell: ({ row }) => {
const value = row.original.value;

return (
<div className="flex items-center gap-1 min-w-[100px]">
<span className="font-medium">{value}</span>
<CommunityLogo
logoUrl={communityConfig.community.logo}
tokenSymbol={communityConfig.primaryToken.symbol}
size={6}
/>
</div>
);
}
},
{
header: 'Description',
accessorKey: 'description',
cell: ({ row }) => {
const description = row.original.description;
return (
<div className="flex items-center gap-1 min-w-[100px]">
<span className="font-medium">{value}</span>
<CommunityLogo
logoUrl={communityConfig.community.logo}
tokenSymbol={communityConfig.primaryToken.symbol}
size={6}
/>
</div>
);
}
},
{
header: 'Description',
accessorKey: 'description',
cell: ({ row }) => {
const description = row.original.description;

return <div className="min-w-[200px] line-clamp-2">{description}</div>;
}
},
{
header: 'Date',
accessorKey: 'created_at',
cell: ({ row }) => {
const createdAt = new Date(row.original.created_at);
return <div className="min-w-[200px] line-clamp-2">{description}</div>;
}
},
{
header: 'Date',
accessorKey: 'created_at',
cell: ({ row }) => {
const createdAt = new Date(row.original.created_at);

return (
<span className="text-muted-foreground text-sm whitespace-nowrap min-w-[150px]">
{createdAt.toLocaleString()}
</span>
);
return (
<span className="text-muted-foreground text-sm whitespace-nowrap min-w-[150px]">
{createdAt.toLocaleString()}
</span>
);
}
}
}
];
];

export const skeletonColumns: ColumnDef<TransferWithMembersT>[] = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use client';

import { DataTable } from '@/components/ui/data-table';
import { Config, CommunityConfig } from '@citizenwallet/sdk';
import { TransferWithMembersT } from '@/services/chain-db/transfers';
import { TransferWithMembersResponseT } from '@/services/chain-db/transfers';
import { CommunityConfig, Config } from '@citizenwallet/sdk';
import { createColumns } from './columns';

interface TransferClientTableProps {
data: TransferWithMembersT[];
data: TransferWithMembersResponseT[];
config: Config;
}

Expand Down
23 changes: 16 additions & 7 deletions app/[alias]/(dashboard)/transfers/_table/transfers-table.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import UrlPagination from '@/components/custom/pagination-via-url';
import { Separator } from '@/components/ui/separator';
import { PAGE_SIZE } from '@/services/chain-db/transfers';
import { getServiceRoleClient } from '@/services/chain-db';
import { getTransfersOfToken, PAGE_SIZE } from '@/services/chain-db/transfers';
import { Config } from '@citizenwallet/sdk';
import { getTransfersOfTokenAction } from '../actions';
import { TransferClientTable } from './transfers-client-table';

interface TransferTableProps {
Expand All @@ -21,30 +21,39 @@ export default async function TransferTable({
config
}: TransferTableProps) {

const { chain_id: chainId, address: tokenAddress } =
config.community.primary_token;

const { data, count: totalCount } = await getTransfersOfTokenAction({
config,
const supabase = getServiceRoleClient(chainId);

const { data, error, count } = await getTransfersOfToken({
client: supabase,
token: tokenAddress,
query,
page,
from,
to
});

const totalPages = Math.ceil(Number(totalCount) / PAGE_SIZE);
if (error) {
console.error(error);
}

const totalPages = Math.ceil(Number(count) / PAGE_SIZE);

return (
<>
<div className="flex-1 overflow-hidden">
<div className="h-full overflow-y-auto rounded-md border">
<TransferClientTable data={data ?? []} config={config} />
<TransferClientTable data={data || []} config={config} />
</div>
</div>

<Separator className="my-4" />

<div className="sticky bottom-0 left-0 right-0 bg-background flex flex-col sm:flex-row justify-between items-center gap-2 pb-4">
<p className="text-sm text-gray-500 whitespace-nowrap">
Total: {Number(totalCount).toLocaleString()}
Total: {Number(count).toLocaleString()}
</p>
<UrlPagination totalPages={totalPages} />
</div>
Expand Down
Loading