Skip to content

Commit

Permalink
feat(wallet-dashboard): add activity list UI (#388)
Browse files Browse the repository at this point in the history
* feat(dashboard): add activity list ui

* fix(dashboard): update styles

* feat(dashboard): add virtual list

* fix(dashboard): rename time util

* feat(dashboard): add new activity interface

* fix(dashboard): modify transactionFailed by the state of the activity

* fix(dashboard): move mock activities to bottom file and rename the container ref

* fix(dashboard): add double quotes to class names

* fix(dashboard): remove space

* fix(dashboard): improve the styles of the virtual list

* fix(dashboard): format files

* fix(dashboard): format files

* fix(dashboard): format time file

* fix(dashboard): missing ;
  • Loading branch information
cpl121 authored May 28, 2024
1 parent caa0430 commit 7449a5a
Show file tree
Hide file tree
Showing 12 changed files with 1,501 additions and 1,027 deletions.
122 changes: 120 additions & 2 deletions apps/wallet-dashboard/app/dashboard/activity/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,130 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

'use client';

import ActivityTile from '@/components/ActivityTile';
import { Activity, ActivityState } from '@/lib/interfaces';
import { useVirtualizer } from '@tanstack/react-virtual';
import React from 'react';

function StakingDashboardPage(): JSX.Element {
const containerRef = React.useRef(null);
const virtualizer = useVirtualizer({
count: MOCK_ACTIVITIES.length,
getScrollElement: () => containerRef.current,
estimateSize: () => 100,
});

const virtualItems = virtualizer.getVirtualItems();

return (
<div className="flex items-center justify-center pt-12">
<h1>ACTIVITY</h1>
<div className="flex h-full w-full flex-col items-center justify-center space-y-4 pt-12">
<h1>Your Activity</h1>
<div className="relative h-[50vh] w-1/3 overflow-auto" ref={containerRef}>
<div
style={{
height: `${virtualizer.getTotalSize()}px`,
width: '100%',
position: 'relative',
}}
>
{virtualItems.map((virtualItem) => {
const activity = MOCK_ACTIVITIES[virtualItem.index];
return (
<div
key={virtualItem.key}
className="absolute w-full pb-4 pr-4"
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${virtualItem.size}px`,
transform: `translateY(${virtualItem.start}px)`,
}}
>
<ActivityTile activity={activity} />
</div>
);
})}
</div>
</div>
</div>
);
}

const MOCK_ACTIVITIES: Activity[] = [
{
action: 'Send',
state: ActivityState.Successful,
timestamp: 1716538921485,
},
{
action: 'Transaction',
state: ActivityState.Successful,
timestamp: 1715868828552,
},
{
action: 'Send',
state: ActivityState.Successful,
timestamp: 1712186639729,
},
{
action: 'Rewards',
state: ActivityState.Successful,
timestamp: 1715868828552,
},
{
action: 'Receive',
state: ActivityState.Successful,
timestamp: 1712186639729,
},
{
action: 'Transaction',
state: ActivityState.Successful,
timestamp: 1715868828552,
},
{
action: 'Send',
state: ActivityState.Failed,
timestamp: 1712186639729,
},
{
action: 'Send',
state: ActivityState.Successful,
timestamp: 1716538921485,
},
{
action: 'Transaction',
state: ActivityState.Successful,
timestamp: 1715868828552,
},
{
action: 'Send',
state: ActivityState.Successful,
timestamp: 1712186639729,
},
{
action: 'Rewards',
state: ActivityState.Successful,
timestamp: 1715868828552,
},
{
action: 'Receive',
state: ActivityState.Successful,
timestamp: 1712186639729,
},
{
action: 'Transaction',
state: ActivityState.Successful,
timestamp: 1715868828552,
},
{
action: 'Send',
state: ActivityState.Failed,
timestamp: 1712186639729,
},
];

export default StakingDashboardPage;
2 changes: 1 addition & 1 deletion apps/wallet-dashboard/app/dashboard/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function DashboardLayout({ children }: PropsWithChildren): JSX.Element {
// TODO: check if the wallet is connected and if not redirect to the welcome screen
return (
<>
<section className="mt-12 flex flex-row items-center justify-around">
<section className="flex flex-row items-center justify-around pt-12">
<ConnectButton />

{routes.map((route) => {
Expand Down
5 changes: 5 additions & 0 deletions apps/wallet-dashboard/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
}
}

html,
body {
height: 100%;
}

body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb)))
Expand Down
55 changes: 55 additions & 0 deletions apps/wallet-dashboard/components/ActivityIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { ActivityState } from '@/lib/interfaces';
import { Account24, ArrowRight16, Sui, Swap16, Unstaked, WalletActionStake24 } from '@mysten/icons';

const icons = {
Send: (
<ArrowRight16
fill="currentColor"
className="text-gradient-blue-start text-body -rotate-45"
/>
),
Receive: (
<ArrowRight16
fill="currentColor"
className="text-gradient-blue-start text-body rotate-135"
/>
),
Transaction: (
<ArrowRight16
fill="currentColor"
className="text-gradient-blue-start text-body -rotate-45"
/>
),
Staked: (
<WalletActionStake24 className="text-gradient-blue-start text-heading2 bg-transparent" />
),
Unstaked: <Unstaked className="text-gradient-blue-start text-heading3" />,
Rewards: <Sui className="text-gradient-blue-start text-body" />,
Swapped: <Swap16 className="text-gradient-blue-start text-heading6" />,
PersonalMessage: (
<Account24 fill="currentColor" className="text-gradient-blue-start text-body" />
),
};

interface ActivityIconProps {
state: ActivityState;
action: keyof typeof icons;
}

function ActivityIcon({ state, action }: ActivityIconProps) {
const isError = state === ActivityState.Failed;
return (
<div
className={`${
isError ? 'bg-issue-light' : 'bg-gray-40'
} w-7.5 h-7.5 rounded-2lg flex items-center justify-center`}
>
{icons[action]}
</div>
);
}

export default ActivityIcon;
28 changes: 28 additions & 0 deletions apps/wallet-dashboard/components/ActivityTile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

'use client';

import React from 'react';
import ActivityIcon from './ActivityIcon';
import formatTimestamp from '@/lib/utils/time';
import { Activity } from '@/lib/interfaces';

interface ActivityTileProps {
activity: Activity;
}

function ActivityTile({ activity: { action, state, timestamp } }: ActivityTileProps): JSX.Element {
return (
<div className="border-gray-45 flex h-full w-full flex-row items-center space-x-4 rounded-md border border-solid p-4">
<ActivityIcon state={state} action={action} />
<div className="flex h-full flex-col space-y-2">
<h2>{action}</h2>
<span>{formatTimestamp(timestamp)}</span>
</div>
<hr />
</div>
);
}

export default ActivityTile;
1 change: 1 addition & 0 deletions apps/wallet-dashboard/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

export { default as RouteLink } from './RouteLink';
export { default as ActivityTile } from './ActivityTile';
export { default as Box } from './Box';
export { default as AmountBox } from './AmountBox';
export { default as List } from './List';
Expand Down
22 changes: 22 additions & 0 deletions apps/wallet-dashboard/lib/interfaces/activities.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export interface Activity {
action:
| 'Send'
| 'Receive'
| 'Transaction'
| 'Staked'
| 'Unstaked'
| 'Rewards'
| 'Swapped'
| 'PersonalMessage';
timestamp: number;
state: ActivityState;
}

export enum ActivityState {
Successful = 'successful',
Failed = 'failed',
Pending = 'pending',
}
4 changes: 4 additions & 0 deletions apps/wallet-dashboard/lib/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './activities.interface';
4 changes: 4 additions & 0 deletions apps/wallet-dashboard/lib/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './time';
7 changes: 7 additions & 0 deletions apps/wallet-dashboard/lib/utils/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export default function formatTimestamp(timeStamp: number): string {
const date = new Date(timeStamp);
return new Intl.DateTimeFormat('en-US').format(date);
}
2 changes: 2 additions & 0 deletions apps/wallet-dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
"@mysten/core": "workspace:*",
"@mysten/dapp-kit": "workspace:*",
"@mysten/sui.js": "workspace:*",
"@mysten/icons": "workspace:*",
"@tanstack/react-query": "^5.0.0",
"@tanstack/react-virtual": "^3.5.0",
"next": "14.2.3",
"react": "^18.2.0",
"zustand": "^4.4.1"
Expand Down
Loading

0 comments on commit 7449a5a

Please sign in to comment.