Skip to content

Commit

Permalink
feat(wallet): rebrand hidden assets (#2012)
Browse files Browse the repository at this point in the history
* feat: kickoff assets page

* feat: refine hidden assets

* feat: fix loop

* feat: determine default category based on available assets

* feat: improvements

* feat: update to filled segmented button
  • Loading branch information
evavirseda authored Aug 27, 2024
1 parent 61b0873 commit 2c716c0
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 103 deletions.
19 changes: 12 additions & 7 deletions apps/ui-kit/src/lib/components/molecules/card/CardAction.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { ArrowRight, ArrowTopRight } from '@iota/ui-icons';
import { ArrowRight } from '@iota/ui-icons';
import { Button, ButtonSize, ButtonType } from '@/components/atoms/button';
import { CardActionType } from './card.enums';

Expand All @@ -10,17 +10,22 @@ export type CardActionProps = {
subtitle?: string;
type: CardActionType;
onClick?: () => void;
isExternalLink?: boolean;
icon?: React.ReactNode;
};

export function CardAction({ type, onClick, subtitle, title, isExternalLink }: CardActionProps) {
export function CardAction({ type, onClick, subtitle, title, icon }: CardActionProps) {
function handleActionClick(event: React.MouseEvent) {
event?.stopPropagation();
onClick?.();
}

if (type === CardActionType.Link) {
return (
<div
onClick={onClick}
className="shrink-0 text-neutral-10 dark:text-neutral-92 [&_svg]:h-6 [&_svg]:w-6"
onClick={handleActionClick}
className="shrink-0 text-neutral-10 dark:text-neutral-92 [&_svg]:h-5 [&_svg]:w-5"
>
{isExternalLink ? <ArrowTopRight /> : <ArrowRight />}
{icon ? icon : <ArrowRight />}
</div>
);
}
Expand Down Expand Up @@ -48,7 +53,7 @@ export function CardAction({ type, onClick, subtitle, title, isExternalLink }: C
type={ButtonType.Outlined}
size={ButtonSize.Small}
text={title}
onClick={onClick}
onClick={handleActionClick}
/>
</div>
);
Expand Down
99 changes: 99 additions & 0 deletions apps/wallet/src/ui/app/pages/home/nfts/HiddenAsset.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { ErrorBoundary } from '_components';
import { ampli } from '_src/shared/analytics/ampli';
import { type IotaObjectData } from '@iota/iota-sdk/client';
import { useNavigate } from 'react-router-dom';
import { useHiddenAssets } from '../assets/HiddenAssetsProvider';
import {
getKioskIdFromOwnerCap,
isKioskOwnerToken,
useGetNFTMeta,
useGetObject,
useKioskClient,
} from '@iota/core';
import {
Card,
CardAction,
CardActionType,
CardBody,
CardImage,
CardType,
ImageShape,
ImageType,
} from '@iota/apps-ui-kit';
import { formatAddress } from '@iota/iota-sdk/utils';
import { useResolveVideo } from '_src/ui/app/hooks/useResolveVideo';
import { VisibilityOff } from '@iota/ui-icons';

export interface HiddenAssetProps {
data: IotaObjectData | null | undefined;
display:
| {
[key: string]: string;
}
| null
| undefined;
}

export default function HiddenAsset(item: HiddenAssetProps) {
const { showAsset } = useHiddenAssets();
const kioskClient = useKioskClient();
const navigate = useNavigate();
const { objectId, type } = item.data!;
const { data: objectData } = useGetObject(objectId);
const { data: nftMeta } = useGetNFTMeta(objectId);

const nftName = nftMeta?.name || formatAddress(objectId);
const nftImageUrl = nftMeta?.imageUrl || '';
const video = useResolveVideo(objectData);

function handleHiddenAssetClick() {
navigate(
isKioskOwnerToken(kioskClient.network, item.data)
? `/kiosk?${new URLSearchParams({
kioskId: getKioskIdFromOwnerCap(item.data!),
})}`
: `/nft-details?${new URLSearchParams({
objectId,
}).toString()}`,
);
ampli.clickedCollectibleCard({
objectId,
collectibleType: type!,
});
}
return (
<ErrorBoundary>
<Card type={CardType.Default} onClick={handleHiddenAssetClick}>
<CardImage type={ImageType.BgTransparent} shape={ImageShape.SquareRounded}>
{video ? (
<video
className="h-full w-full object-cover"
src={video}
controls
autoPlay
muted
/>
) : (
<img
src={nftImageUrl}
alt={nftName}
className="h-full w-full object-cover"
/>
)}
</CardImage>
<CardBody title={nftMeta?.name ?? 'Asset'} subtitle={formatAddress(objectId)} />
<CardAction
type={CardActionType.Link}
onClick={() => {
showAsset(objectId);
}}
icon={<VisibilityOff />}
/>
</Card>
</ErrorBoundary>
);
}
68 changes: 4 additions & 64 deletions apps/wallet/src/ui/app/pages/home/nfts/HiddenAssets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,16 @@
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { ErrorBoundary, NFTDisplayCard } from '_components';
import { ampli } from '_src/shared/analytics/ampli';
import { Button } from '_src/ui/app/shared/ButtonUI';
import { EyeClose16 } from '@iota/icons';
import { type IotaObjectData } from '@iota/iota-sdk/client';
import { Link } from 'react-router-dom';
import { useHiddenAssets } from '../assets/HiddenAssetsProvider';
import { getKioskIdFromOwnerCap, isKioskOwnerToken, useKioskClient } from '@iota/core';
import HiddenAsset, { type HiddenAssetProps } from './HiddenAsset';

interface HiddenAssetsProps {
items: {
data: IotaObjectData | null | undefined;
display:
| {
[key: string]: string;
}
| null
| undefined;
}[];
items: HiddenAssetProps[];
}

export default function HiddenAssets({ items }: HiddenAssetsProps) {
const { showAsset } = useHiddenAssets();
const kioskClient = useKioskClient();

return (
<div className="grid w-full grid-cols-2 gap-x-3.5 gap-y-4">
{items?.map((object) => {
const { objectId, type } = object.data!;
return (
<div className="flex items-center justify-between pr-1 pt-2" key={objectId}>
<Link
to={
isKioskOwnerToken(kioskClient.network, object.data)
? `/kiosk?${new URLSearchParams({
kioskId: getKioskIdFromOwnerCap(object.data!),
})}`
: `/nft-details?${new URLSearchParams({
objectId,
}).toString()}`
}
onClick={() => {
ampli.clickedCollectibleCard({
objectId,
collectibleType: type!,
});
}}
className="relative truncate no-underline"
>
<ErrorBoundary>
<NFTDisplayCard
objectId={objectId}
size="xs"
orientation="horizontal"
/>
</ErrorBoundary>
</Link>
<div className="h-8 w-8">
<Button
variant="secondaryIota"
size="icon"
onClick={() => {
showAsset(objectId);
}}
after={<EyeClose16 />}
/>
</div>
</div>
);
})}
<div className="flex w-full flex-col overflow-y-auto">
{items?.map((object) => <HiddenAsset key={object.data!.objectId} {...object} />)}
</div>
);
}
6 changes: 5 additions & 1 deletion apps/wallet/src/ui/app/pages/home/nfts/NonVisualAssets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ExplorerLink, ExplorerLinkType } from '_components';
import { type IotaObjectData } from '@iota/iota-sdk/client';
import { formatAddress, parseStructTag } from '@iota/iota-sdk/utils';
import { Card, CardAction, CardActionType, CardBody, CardType } from '@iota/apps-ui-kit';
import { ArrowTopRight } from '@iota/ui-icons';

interface NonVisualAssetsProps {
items: IotaObjectData[];
Expand All @@ -30,7 +31,10 @@ export default function NonVisualAssets({ items }: NonVisualAssetsProps) {
title={formatAddress(item.objectId!)}
subtitle={`${formatAddress(address)}::${module}::${name}`}
/>
<CardAction type={CardActionType.Link} isExternalLink />
<CardAction
type={CardActionType.Link}
icon={<ArrowTopRight />}
/>
</Card>
</ExplorerLink>
);
Expand Down
63 changes: 33 additions & 30 deletions apps/wallet/src/ui/app/pages/home/nfts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,25 +133,26 @@ function NftsPage() {
return (
<PageTemplate title="Assets" isTitleCentered>
<div className="flex h-full w-full flex-col items-start gap-md">
{isAssetsLoaded && (filteredAssets.length || filteredHiddenAssets.length) && (
<SegmentedButton type={SegmentedButtonType.Filled}>
{ASSET_CATEGORIES.map(({ label, value }) => (
<ButtonSegment
key={value}
onClick={() => setSelectedAssetCategory(value)}
label={label}
selected={selectedAssetCategory === value}
disabled={
AssetCategory.Hidden === value
? !hiddenAssetIds.length
: AssetCategory.Visual === value
? !ownedAssets?.visual.length
: !ownedAssets?.other.length
}
/>
))}
</SegmentedButton>
)}
{isAssetsLoaded &&
Boolean(filteredAssets.length || filteredHiddenAssets.length) && (
<SegmentedButton type={SegmentedButtonType.Filled}>
{ASSET_CATEGORIES.map(({ label, value }) => (
<ButtonSegment
key={value}
onClick={() => setSelectedAssetCategory(value)}
label={label}
selected={selectedAssetCategory === value}
disabled={
AssetCategory.Hidden === value
? !hiddenAssetIds.length
: AssetCategory.Visual === value
? !ownedAssets?.visual.length
: !ownedAssets?.other.length
}
/>
))}
</SegmentedButton>
)}
<Loading loading={isPending}>
{isError ? (
<Alert>
Expand All @@ -161,17 +162,19 @@ function NftsPage() {
<small>{(error as Error).message}</small>
</Alert>
) : null}
{selectedAssetCategory === AssetCategory.Visual ? (
<VisualAssets items={filteredAssets} />
) : selectedAssetCategory === AssetCategory.Other ? (
<NonVisualAssets items={filteredAssets} />
) : selectedAssetCategory === AssetCategory.Hidden ? (
<HiddenAssets items={filteredHiddenAssets} />
) : (
<div className="text-steel-darker flex flex-1 items-center self-center text-caption font-semibold">
No Assets found
</div>
)}
<div className="flex h-full w-full flex-col">
{selectedAssetCategory === AssetCategory.Visual ? (
<VisualAssets items={filteredAssets} />
) : selectedAssetCategory === AssetCategory.Other ? (
<NonVisualAssets items={filteredAssets} />
) : selectedAssetCategory === AssetCategory.Hidden ? (
<HiddenAssets items={filteredHiddenAssets} />
) : (
<div className="text-steel-darker flex flex-1 items-center self-center text-caption font-semibold">
No Assets found
</div>
)}
</div>
</Loading>
<div ref={observerElem}>
{isSpinnerVisible ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export function PageMainLayout({
rightContent={topNavMenuEnabled ? <WalletSettingsButton /> : undefined}
/>
) : null}

<div className="relative flex flex-grow flex-col flex-nowrap overflow-hidden">
<div className="flex flex-grow flex-col flex-nowrap overflow-y-auto overflow-x-hidden bg-neutral-100">
<main
Expand Down

0 comments on commit 2c716c0

Please sign in to comment.