Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wallet-dashboard): add styles for non visual assets #3761

Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b0c9983
feat(wallet-dashboard): add protected layout
VmMad Oct 25, 2024
670f496
feat: add missing TopNav
VmMad Oct 28, 2024
d43a921
fix: tests
VmMad Oct 28, 2024
5ba9405
Merge branch 'develop' into tooling-dashboard/add-connected-layout
VmMad Oct 28, 2024
1100c2c
fix: imports
VmMad Oct 28, 2024
0f30b19
Merge branch 'develop' into tooling-dashboard/add-connected-layout
evavirseda Oct 28, 2024
a74ff0e
feat(wallet-dashboard): add assets page
VmMad Oct 28, 2024
9d4abe6
Merge branch 'tooling-dashboard/add-connected-layout' into tooling-da…
VmMad Oct 28, 2024
37ce97e
fix: add missing themes
VmMad Oct 28, 2024
8a8f711
Merge branch 'tooling-dashboard/add-connected-layout' into tooling-da…
VmMad Oct 28, 2024
6de4fc2
feat: improve connect button size
VmMad Oct 28, 2024
bc4612b
revert: "feat: improve connect button size"
VmMad Oct 28, 2024
516126f
Merge branch 'develop' into tooling-dashboard/add-assets-layout
VmMad Oct 29, 2024
551b48f
feat(wallet-dashboard): add grid for visual assets
VmMad Oct 29, 2024
546ac20
feat(Wallet-dashboard): add styles for non visual assets
VmMad Oct 29, 2024
ea32c22
refactor: remove unnecessary useMemo
VmMad Oct 30, 2024
8b5348a
fix: remove commented lines
VmMad Oct 30, 2024
f6ddc10
Merge branch 'develop' into tooling-dashboard/add-assets-layout
evavirseda Oct 30, 2024
a4db526
Merge branch 'tooling-dashboard/add-assets-layout' into tooling-dashb…
VmMad Nov 4, 2024
0753921
fix: improve type
VmMad Nov 6, 2024
f0131a0
Merge branch 'develop' into tooling-dashboard/add-assets-styles
VmMad Nov 6, 2024
9c5032e
fix: update IotaLogo
VmMad Nov 6, 2024
c88f22f
Merge branch 'tooling-dashboard/add-assets-styles' into tooling-dashb…
cpl121 Nov 6, 2024
eca8997
refactor: use explorer link and remove unnecessary code
VmMad Nov 7, 2024
f05b525
Merge branch 'develop' into tooling-dashboard/add-other-assets-styles
VmMad Nov 7, 2024
3540091
fix: bring back more details for visual sset details
VmMad Nov 7, 2024
889fe4e
fix: update to make it as reviewed
VmMad Nov 7, 2024
92f2afa
refactor: move explorer link generation logic to core
VmMad Nov 7, 2024
c1c5264
fix: update imports
VmMad Nov 7, 2024
79e89ba
fix: copy comment
VmMad Nov 8, 2024
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
1 change: 1 addition & 0 deletions apps/core/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ export * from './useUnlockTimelockedObjectsTransaction';
export * from './useGetAllOwnedObjects';
export * from './useGetTimelockedStakedObjects';
export * from './useGetActiveValidatorsInfo';
export * from './useCursorPagination';

export * from './stake';
56 changes: 56 additions & 0 deletions apps/core/src/hooks/useCursorPagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { useState } from 'react';
import { type InfiniteData, type UseInfiniteQueryResult } from '@tanstack/react-query';

interface PaginationProps {
hasFirst: boolean;
hasPrev: boolean;
hasNext: boolean;
onFirst(): void;
onPrev(): void;
onNext(): void;
}

interface CursorPaginationProps extends PaginationProps {
currentPage: number;
}

export interface PaginationResponse<Cursor = string> {
nextCursor: Cursor | null;
hasNextPage: boolean;
}

export function useCursorPagination<T>(query: UseInfiniteQueryResult<InfiniteData<T>>) {
const [currentPage, setCurrentPage] = useState(0);

return {
...query,
data: query.data?.pages[currentPage],
pagination: {
onFirst: () => setCurrentPage(0),
onNext: () => {
if (!query.data || query.isFetchingNextPage) {
return;
}

// Make sure we are at the end before fetching another page
if (currentPage >= query.data.pages.length - 1) {
query.fetchNextPage();
}

setCurrentPage(currentPage + 1);
},
onPrev: () => {
setCurrentPage(Math.max(currentPage - 1, 0));
},
hasFirst: currentPage !== 0,
hasNext:
!query.isFetchingNextPage &&
(currentPage < (query.data?.pages.length ?? 0) - 1 || !!query.hasNextPage),
hasPrev: currentPage !== 0,
currentPage,
} satisfies CursorPaginationProps,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

import { InfoBox, InfoBoxStyle, InfoBoxType, Select, SelectSize } from '@iota/apps-ui-kit';
import { useIotaClientQuery, useIotaClient, useIotaClientInfiniteQuery } from '@iota/dapp-kit';
import { useCursorPagination } from '@iota/core';
import { Warning } from '@iota/ui-icons';
import { useQuery } from '@tanstack/react-query';
import { useState } from 'react';
import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui';
import { PlaceholderTable, TableCard } from '~/components/ui';
import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants';
import { generateEpochsTableColumns } from '~/lib/ui';
import { numberSuffix } from '~/lib/utils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import { useIotaClient } from '@iota/dapp-kit';
import { useQuery } from '@tanstack/react-query';
import { useEffect, useRef, useState } from 'react';
import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui';
import { PlaceholderTable, TableCard } from '~/components/ui';
import { useCursorPagination } from '@iota/core';
import {
DEFAULT_TRANSACTIONS_LIMIT,
useGetTransactionBlocks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import { InfoBox, InfoBoxStyle, InfoBoxType, Select, SelectSize } from '@iota/ap
import { useIotaClientQuery } from '@iota/dapp-kit';
import { Warning } from '@iota/ui-icons';
import { useMemo, useState } from 'react';
import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui';
import { PlaceholderTable, TableCard } from '~/components/ui';
import { DEFAULT_CHECKPOINTS_LIMIT, useGetCheckpoints } from '~/hooks/useGetCheckpoints';
import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants';
import { generateCheckpointsTableColumns } from '~/lib/ui';
import { numberSuffix } from '~/lib/utils';
import { useCursorPagination } from '@iota/core';

interface CheckpointsTableProps {
disablePagination?: boolean;
Expand Down
9 changes: 7 additions & 2 deletions apps/explorer/src/components/owned-objects/OwnedObjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { useGetKioskContents, useGetOwnedObjects, useLocalStorage } from '@iota/core';
import {
useGetKioskContents,
useGetOwnedObjects,
useLocalStorage,
useCursorPagination,
} from '@iota/core';
import {
Button,
ButtonSize,
Expand All @@ -27,7 +32,7 @@ import clsx from 'clsx';
import { useEffect, useMemo, useState } from 'react';
import { ListView, SmallThumbnailsView, ThumbnailsView } from '~/components';
import { ObjectViewMode } from '~/lib/enums';
import { Pagination, useCursorPagination } from '~/components/ui';
import { Pagination } from '~/components/ui';
import { PAGE_SIZES_RANGE_10_50 } from '~/lib/constants';

const SHOW_PAGINATION_MAX_ITEMS = 9;
Expand Down
40 changes: 1 addition & 39 deletions apps/explorer/src/components/ui/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import { Button, ButtonSize, ButtonType } from '@iota/apps-ui-kit';
import { ArrowLeft, ArrowRight, DoubleArrowLeft } from '@iota/ui-icons';
import { type InfiniteData, type UseInfiniteQueryResult } from '@tanstack/react-query';
import { useState } from 'react';

interface PaginationProps {
Expand All @@ -16,49 +15,12 @@ interface PaginationProps {
onNext(): void;
}

interface CursorPaginationProps extends PaginationProps {
currentPage: number;
}

export interface PaginationResponse<Cursor = string> {
nextCursor: Cursor | null;
hasNextPage: boolean;
}

export function useCursorPagination<T>(query: UseInfiniteQueryResult<InfiniteData<T>>) {
const [currentPage, setCurrentPage] = useState(0);

return {
...query,
data: query.data?.pages[currentPage],
pagination: {
onFirst: () => setCurrentPage(0),
onNext: () => {
if (!query.data || query.isFetchingNextPage) {
return;
}

// Make sure we are at the end before fetching another page
if (currentPage >= query.data.pages.length - 1) {
query.fetchNextPage();
}

setCurrentPage(currentPage + 1);
},
onPrev: () => {
setCurrentPage(Math.max(currentPage - 1, 0));
},
hasFirst: currentPage !== 0,
hasNext:
!query.isFetchingNextPage &&
(currentPage < (query.data?.pages.length ?? 0) - 1 || !!query.hasNextPage),
hasPrev: currentPage !== 0,
currentPage,
} satisfies CursorPaginationProps,
};
}

/** @deprecated Prefer `useCursorPagination` + `useInfiniteQuery` for pagination. */
/** @deprecated Prefer `useCursorPagination` from core + `useInfiniteQuery` for pagination. */
export function usePaginationStack<Cursor = string>() {
const [stack, setStack] = useState<Cursor[]>([]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

import { DropdownPosition, Select, SelectSize } from '@iota/apps-ui-kit';
import { useState } from 'react';
import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui';
import { PlaceholderTable, TableCard } from '~/components/ui';
import { useCursorPagination } from '@iota/core';
import {
DEFAULT_TRANSACTIONS_LIMIT,
useGetTransactionBlocks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AssetCard, Button, RouteLink, SendAssetPopup } from '@/components';
import { isAssetTransferable, useGetObject } from '@iota/core';
import { usePopups } from '@/hooks';
import { useCurrentAccount } from '@iota/dapp-kit';
import { ASSETS_ROUTE } from '@/lib/constants/routes.constants';

const VisualAssetDetailPage = () => {
const params = useParams();
Expand All @@ -28,7 +29,7 @@ const VisualAssetDetailPage = () => {

return (
<div className="flex h-full w-full flex-col space-y-4 px-40">
<RouteLink path="/dashboard/assets/visual-assets" title="Back" />
<RouteLink path={ASSETS_ROUTE.path} title="Back" />
{asset?.data ? (
<AssetCard key={asset.data.objectId} asset={asset.data} />
) : (
Expand Down
103 changes: 103 additions & 0 deletions apps/wallet-dashboard/app/(protected)/assets/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

'use client';

import { PageSizeSelector, PaginationOptions } from '@/components';
import { Panel, Title, Chip, TitleSize, DropdownPosition } from '@iota/apps-ui-kit';
import { hasDisplayData, useCursorPagination, useGetOwnedObjects } from '@iota/core';
import { useCurrentAccount } from '@iota/dapp-kit';
import { IotaObjectData } from '@iota/iota-sdk/client';
import { useMemo, useState } from 'react';
import { AssetCategory } from '@/lib/enums';
import { AssetList } from '@/components/AssetsList';

const PAGINATION_RANGE = [20, 40, 60];

const ASSET_CATEGORIES: { label: string; value: AssetCategory }[] = [
{
label: 'Visual',
value: AssetCategory.Visual,
},
{
label: 'Other',
value: AssetCategory.Other,
},
// {
// label: 'Hidden',
// value: AssetCategory.Hidden,
// },
];

export default function AssetsDashboardPage(): React.JSX.Element {
const [selectedCategory, setSelectedCategory] = useState<AssetCategory>(AssetCategory.Visual);
const [limit, setLimit] = useState<number>(PAGINATION_RANGE[1]);

const account = useCurrentAccount();
const ownedObjectsQuery = useGetOwnedObjects(account?.address, undefined, limit);

const { data, pagination } = useCursorPagination(ownedObjectsQuery);

const { data: ownedObjects } = data || {};

const [visual, nonVisual] = useMemo(() => {
const visual: IotaObjectData[] = [];
const nonVisual: IotaObjectData[] = [];

ownedObjects
?.filter((asset) => asset.data && asset.data.objectId)
.forEach((asset) => {
if (asset.data) {
if (hasDisplayData(asset)) {
visual.push(asset.data);
} else {
nonVisual.push(asset.data);
}
}
});

return [visual, nonVisual];
}, [ownedObjects]);

const categoryToAsset: Record<AssetCategory, IotaObjectData[]> = {
[AssetCategory.Visual]: visual,
[AssetCategory.Other]: nonVisual,
// [AssetCategory.Hidden]: [],
};

const assetList = categoryToAsset[selectedCategory];

return (
<Panel>
<Title title="Assets" size={TitleSize.Medium} />
<div className="px-lg">
<div className="flex flex-row items-center justify-start gap-xs py-xs">
{ASSET_CATEGORIES.map((tab) => (
<Chip
key={tab.label}
label={tab.label}
onClick={() => setSelectedCategory(tab.value)}
selected={selectedCategory === tab.value}
/>
))}
</div>

<AssetList assets={assetList} selectedCategory={selectedCategory} />
<div className="flex flex-row items-center justify-end py-xs">
<PaginationOptions
pagination={pagination}
action={
<PageSizeSelector
pagination={pagination}
range={PAGINATION_RANGE}
dropdownPosition={DropdownPosition.Top}
setLimit={(e) => setLimit(e)}
limit={limit.toString()}
/>
}
/>
</div>
</div>
</Panel>
);
}
4 changes: 4 additions & 0 deletions apps/wallet-dashboard/app/(protected)/components/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 './sidebar/Sidebar';
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { PROTECTED_ROUTES } from '@/lib/constants/routes.constants';
import { IotaLogoMark } from '@iota/ui-icons';
import { SidebarItem } from './SidebarItem';

export function Sidebar() {
return (
<nav className="flex h-screen flex-col items-center gap-y-2xl bg-neutral-100 py-xl dark:bg-neutral-6">
<IotaLogoMark className="h-10 w-10 text-neutral-10 dark:text-neutral-92" />
<div className="flex flex-col gap-y-xs">
{PROTECTED_ROUTES.map((route) => (
<SidebarItem key={route.path} {...route} />
))}
</div>
</nav>
);
}
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

'use client';

import type { ProtectedRoute } from '@/lib/interfaces';
import { NavbarItem, Tooltip, TooltipPosition } from '@iota/apps-ui-kit';
import { usePathname } from 'next/navigation';
import Link from 'next/link';

export function SidebarItem({ icon, title, path }: ProtectedRoute) {
const pathname = usePathname();
const RouteIcon = icon;
const isActive = pathname === path;
return (
<Tooltip text={title} position={TooltipPosition.Right}>
<Link href={path} className="relative px-sm py-xxs">
<NavbarItem isSelected={isActive} icon={<RouteIcon />} />
</Link>
</Tooltip>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { Badge, BadgeType, Button, ButtonType } from '@iota/apps-ui-kit';
import { ConnectButton } from '@iota/dapp-kit';
import { Settings } from '@iota/ui-icons';

export function TopNav() {
return (
<div className="flex h-[52px] w-full flex-row items-center justify-end gap-md py-xs--rs">
<Badge label="Mainnet" type={BadgeType.PrimarySoft} />
<ConnectButton />
<Button icon={<Settings />} type={ButtonType.Ghost} />
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function HomeDashboardPage(): JSX.Element {
};

return (
<main className="flex min-h-screen flex-col items-center space-y-8 p-24">
<main className="flex flex-1 flex-col items-center space-y-8 p-24">
<p>Connection status: {connectionStatus}</p>
{connectionStatus === 'connected' && account && (
<div className="flex flex-col items-center justify-center space-y-2">
Expand Down
Loading
Loading