Skip to content

Commit

Permalink
feat(wallet-dashboard): add styles for non visual assets (#3761)
Browse files Browse the repository at this point in the history
* feat(wallet-dashboard): add protected layout

* feat: add missing TopNav

* fix: tests

* fix: imports

* feat(wallet-dashboard): add assets page

* fix: add missing themes

* feat: improve connect button size

* revert: "feat: improve connect button size"

* feat(wallet-dashboard): add grid for visual assets

* feat(Wallet-dashboard): add styles for non visual assets

* refactor: remove unnecessary useMemo

* fix: remove commented lines

* fix: improve type

* fix: update IotaLogo

* refactor: use explorer link and remove unnecessary code

* fix: bring back more details for visual sset details

* fix: update to make it as reviewed

* refactor: move explorer link generation logic to core

* fix: update imports

* fix: copy comment

---------

Co-authored-by: evavirseda <[email protected]>
Co-authored-by: cpl121 <[email protected]>
  • Loading branch information
3 people authored Nov 8, 2024
1 parent f59220d commit 90fdcf7
Show file tree
Hide file tree
Showing 37 changed files with 293 additions and 143 deletions.
File renamed without changes.
4 changes: 4 additions & 0 deletions apps/core/src/enums/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 './ExplorerLinkType';
1 change: 1 addition & 0 deletions apps/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: Apache-2.0

export * from './api';
export * from './enums';
export * from './components';
export * from './utils';
export * from './hooks';
Expand Down
File renamed without changes.
58 changes: 58 additions & 0 deletions apps/core/src/utils/getExplorerLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { getCustomNetwork } from '.';
import { getNetwork, Network, NetworkId } from '@iota/iota-sdk/client';
import { getAddressUrl, getObjectUrl, getTransactionUrl, getValidatorUrl } from '.';
import { ExplorerLinkType } from '../enums';

export type ExplorerLinkConfig =
| {
type: ExplorerLinkType.Address;
address?: string;
useActiveAddress?: false;
}
| {
type: ExplorerLinkType.Address;
useActiveAddress: true;
}
| { type: ExplorerLinkType.Object; objectID: string; moduleName?: string }
| { type: ExplorerLinkType.Transaction; transactionID: string }
| { type: ExplorerLinkType.Validator; validator: string };

function getAddress(linkConfig: ExplorerLinkConfig, activeAddress: string | null) {
const { type } = linkConfig;
const isAddress = type === ExplorerLinkType.Address;
const isProvidedAddress = isAddress && !linkConfig.useActiveAddress;
return isProvidedAddress ? linkConfig.address : activeAddress;
}

export function getExplorerLink(
linkConfig: ExplorerLinkConfig,
activeAddress: string | null,
network: NetworkId,
) {
const { type } = linkConfig;
const address = getAddress(linkConfig, activeAddress);
const objectID = type === ExplorerLinkType.Object ? linkConfig.objectID : null;
const transactionID = type === ExplorerLinkType.Transaction ? linkConfig.transactionID : null;
const validator = type === ExplorerLinkType.Validator ? linkConfig.validator : null;
const moduleName = type === ExplorerLinkType.Object ? linkConfig.moduleName : null;

// fallback to localhost if customRPC is not set
const customExplorer =
network === Network.Custom ? getCustomNetwork().explorer : getNetwork(network).explorer;

if (!address) return null;
switch (type) {
case ExplorerLinkType.Address:
return address && getAddressUrl(address, network, customExplorer);
case ExplorerLinkType.Object:
return objectID && getObjectUrl(objectID, network, customExplorer, moduleName);
case ExplorerLinkType.Transaction:
return transactionID && getTransactionUrl(transactionID, network, customExplorer);
case ExplorerLinkType.Validator:
return validator && getValidatorUrl(validator, network, customExplorer);
}
}
47 changes: 47 additions & 0 deletions apps/core/src/utils/getExplorerPaths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { getNetwork, Network, NetworkId } from '@iota/iota-sdk/client';

function getExplorerUrl(
path: string,
network: NetworkId,
customExplorer: string,
getUrlWithDeviceId: (url: URL) => URL = (url) => url,
) {
const networkConfig = getNetwork(network);
const explorer = network === Network.Custom ? customExplorer : networkConfig?.explorer;

const url = getUrlWithDeviceId(new URL(path, explorer));
if (explorer) {
url.searchParams.append('network', network);
}

return url.href;
}

export function getObjectUrl(
objectID: string,
network: NetworkId,
customExplorer: string,
moduleName?: string | null,
) {
return getExplorerUrl(
`/object/${objectID}${moduleName ? `?module=${moduleName}` : ''}`,
network,
customExplorer,
);
}

export function getTransactionUrl(txDigest: string, network: NetworkId, customExplorer: string) {
return getExplorerUrl(`/txblock/${encodeURIComponent(txDigest)}`, network, customExplorer);
}

export function getAddressUrl(address: string, network: NetworkId, customExplorer: string) {
return getExplorerUrl(`/address/${address}`, network, customExplorer);
}

export function getValidatorUrl(address: string, network: NetworkId, customExplorer: string) {
return getExplorerUrl(`/validator/${address}`, network, customExplorer);
}
3 changes: 3 additions & 0 deletions apps/core/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export * from './filterAndSortTokenBalances';
export * from './getOwnerDisplay';
export * from './parseAmount';
export * from './parseObjectDetails';
export * from './api-env';
export * from './getExplorerPaths';
export * from './getExplorerLink';

export * from './stake';
export * from './transaction';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import React, { useCallback } from 'react';
import { useParams } from 'next/navigation';
import { AssetCard, Button, RouteLink, SendAssetPopup } from '@/components';
import { Button, RouteLink, SendAssetPopup, VisualAssetDetailsCard } from '@/components';
import { isAssetTransferable, useGetObject } from '@iota/core';
import { usePopups } from '@/hooks';
import { useCurrentAccount } from '@iota/dapp-kit';
Expand All @@ -31,7 +31,7 @@ const VisualAssetDetailPage = () => {
<div className="flex h-full w-full flex-col space-y-4 px-40">
<RouteLink path={ASSETS_ROUTE.path} title="Back" />
{asset?.data ? (
<AssetCard key={asset.data.objectId} asset={asset.data} />
<VisualAssetDetailsCard key={asset.data.objectId} asset={asset.data} />
) : (
<div className="flex justify-center p-20">Asset not found</div>
)}
Expand Down
21 changes: 3 additions & 18 deletions apps/wallet-dashboard/app/(protected)/assets/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@

'use client';

import { AssetCard, PageSizeSelector, PaginationOptions } from '@/components';
import { ASSETS_ROUTE } from '@/lib/constants/routes.constants';
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 { useState } from 'react';
import { AssetCategory } from '@/lib/enums';
import { VisibilityOff } from '@iota/ui-icons';
import { useRouter } from 'next/navigation';
import { AssetList } from '@/components/AssetsList';

const PAGINATION_RANGE = [20, 40, 60];

Expand All @@ -30,7 +28,6 @@ const ASSET_CATEGORIES: { label: string; value: AssetCategory }[] = [
export default function AssetsDashboardPage(): React.JSX.Element {
const [selectedCategory, setSelectedCategory] = useState<AssetCategory>(AssetCategory.Visual);
const [limit, setLimit] = useState<number>(PAGINATION_RANGE[1]);
const router = useRouter();

const account = useCurrentAccount();
const ownedObjectsQuery = useGetOwnedObjects(account?.address, undefined, limit);
Expand Down Expand Up @@ -80,19 +77,7 @@ export default function AssetsDashboardPage(): React.JSX.Element {
))}
</div>

<div className="grid-template-visual-assets grid max-h-[600px] gap-md overflow-auto py-sm">
{assetList.map((asset) => (
<div key={asset.digest}>
<AssetCard
asset={asset}
icon={<VisibilityOff />}
onClick={() =>
router.push(ASSETS_ROUTE.path + `/${asset.objectId}`)
}
/>
</div>
))}
</div>
<AssetList assets={assetList} selectedCategory={selectedCategory} />
<div className="flex flex-row items-center justify-end py-xs">
<PaginationOptions
pagination={pagination}
Expand Down

This file was deleted.

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

import { AssetCategory } from '@/lib/enums';
import { IotaObjectData } from '@iota/iota-sdk/client';
import { AssetTileLink } from '@/components';

interface AssetListProps {
assets: IotaObjectData[];
selectedCategory: AssetCategory;
}

const ASSET_LAYOUT: Record<AssetCategory, string> = {
[AssetCategory.Visual]:
'grid-template-visual-assets grid max-h-[600px] gap-md overflow-auto py-sm',
[AssetCategory.Other]: 'flex flex-col overflow-auto py-sm',
};

export function AssetList({ assets, selectedCategory }: AssetListProps): React.JSX.Element {
return (
<div className={ASSET_LAYOUT[selectedCategory]}>
{assets.map((asset) => (
<AssetTileLink key={asset.digest} asset={asset} type={selectedCategory} />
))}
</div>
);
}
23 changes: 23 additions & 0 deletions apps/wallet-dashboard/components/Cards/VisualAssetDetailsCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { IotaObjectData } from '@iota/iota-sdk/client';
import { VisualAssetTile } from '../tiles';

interface AssetDetailsCardProps {
asset: IotaObjectData;
}

export function VisualAssetDetailsCard({ asset }: AssetDetailsCardProps): React.JSX.Element {
return (
<div className="flex w-full gap-2">
<VisualAssetTile asset={asset} />
<div>
<p>Digest: {asset.digest}</p>
<p>Object ID: {asset.objectId}</p>
{asset.type ? <p>Type: {asset.type}</p> : null}
<p>Version: {asset.version}</p>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion apps/wallet-dashboard/components/Cards/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
// SPDX-License-Identifier: Apache-2.0

export { default as StakeCard } from './StakeCard';
export * from './AssetCard';
export * from './VisualAssetDetailsCard';
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import React, { useCallback, useState } from 'react';
import { IotaObjectData } from '@iota/iota-sdk/client';
import { AssetCard, Input } from '@/components';
import { VisualAssetTile, Input } from '@/components';
import { Button } from '@/components/Buttons';
import { FlexDirection } from '@/lib/ui/enums';
import { useCurrentAccount } from '@iota/dapp-kit';
Expand Down Expand Up @@ -49,7 +49,7 @@ export default function SendAssetPopup({ asset, onClose }: SendAssetPopupProps):
function onSendAssetSuccess() {
addNotification('Transfer transaction successful', NotificationType.Success);
onClose?.();
router.push(ASSETS_ROUTE.path + '/visual-assets');
router.push(ASSETS_ROUTE.path + '/assets');
}

function onSendAssetError() {
Expand All @@ -67,7 +67,7 @@ export default function SendAssetPopup({ asset, onClose }: SendAssetPopupProps):

return (
<div className="flex flex-col space-y-4">
<AssetCard asset={asset} flexDirection={FlexDirection.Column} />
<VisualAssetTile asset={asset} flexDirection={FlexDirection.Column} />
<div className="flex flex-col space-y-2">
<Input
type="text"
Expand Down
1 change: 1 addition & 0 deletions apps/wallet-dashboard/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from './transactions';
export * from './staking-overview';
export * from './Dialogs';
export * from './ImageIcon';
export * from './tiles';
52 changes: 52 additions & 0 deletions apps/wallet-dashboard/components/tiles/AssetTileLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

'use client';

import { ASSETS_ROUTE } from '@/lib/constants/routes.constants';
import { AssetCategory } from '@/lib/enums';
import { VisibilityOff } from '@iota/ui-icons';
import { VisualAssetTile } from '.';
import { IotaObjectData } from '@iota/iota-sdk/client';
import { NonVisualAssetCard } from './NonVisualAssetTile';
import { useExplorerLinkGetter } from '@/hooks';
import Link from 'next/link';
import { ExplorerLinkType } from '@iota/core';

interface AssetTileLinkProps {
asset: IotaObjectData;
type: AssetCategory;
}

export function AssetTileLink({ asset, type }: AssetTileLinkProps): React.JSX.Element {
const getExplorerLink = useExplorerLinkGetter();
const linkProps = getAssetLinkProps(asset);

function getAssetLinkProps(asset: IotaObjectData): React.ComponentProps<typeof Link> {
if (type === AssetCategory.Visual) {
return { href: ASSETS_ROUTE.path + `/${asset.objectId}` };
} else {
const explorerLink =
getExplorerLink({
type: ExplorerLinkType.Object,
objectID: asset.objectId,
}) ?? '';

return {
href: explorerLink,
target: '_blank',
rel: 'noopener noreferrer',
};
}
}

return (
<Link {...linkProps}>
{type === AssetCategory.Visual ? (
<VisualAssetTile asset={asset} icon={<VisibilityOff />} />
) : (
<NonVisualAssetCard asset={asset} />
)}
</Link>
);
}
Loading

0 comments on commit 90fdcf7

Please sign in to comment.