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): show kiosk NFTs #4610

Open
wants to merge 40 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
bf71636
refactor(wallet): move notification to separate component.
panteleymonchuk Dec 16, 2024
bc69f2f
feat(wallet): enhance hidden asset functionality with undo option and…
panteleymonchuk Dec 16, 2024
351bfe4
feat(wallet): add undo functionality for showing hidden assets with n…
panteleymonchuk Dec 16, 2024
a7a42f7
feat(core): move HiddenAssetsProvider.
panteleymonchuk Dec 16, 2024
0b491ad
feat(core): move useGetNFTs.
panteleymonchuk Dec 16, 2024
5137f19
feat(core): update useGetNFTs to accept filter and improve asset fetc…
panteleymonchuk Dec 16, 2024
5185c8d
Merge remote-tracking branch 'origin/develop' into tooling-dashboard/…
panteleymonchuk Dec 17, 2024
70752dd
refactor(dashboard): remove 'Hidden' asset category and related logic
panteleymonchuk Dec 18, 2024
73f2001
refactor(wallet-dashboard): remove 'Hidden' asset category from layout
panteleymonchuk Dec 18, 2024
9537c65
refactor(dashboard): remove HiddenAssets context, update default sele…
panteleymonchuk Dec 18, 2024
47a7033
Merge remote-tracking branch 'origin/develop' into tooling-dashboard/…
panteleymonchuk Dec 18, 2024
90e0791
feat(core): add refetch capability to useGetNFTs hook
panteleymonchuk Dec 18, 2024
1647efa
Merge branch 'develop' into tooling-dashboard/improve-asset-filter
panteleymonchuk Dec 18, 2024
2a08552
refactor(core): improve hide/show logic
panteleymonchuk Dec 20, 2024
2939b92
refactor(core): remove undo functionality and streamline asset visibi…
panteleymonchuk Dec 20, 2024
f12a355
refactor(core): simplify asset visibility management and improve erro…
panteleymonchuk Dec 20, 2024
600373a
refactor(wallet): rename MoveAssetNotification to MovedAssetNotification
panteleymonchuk Dec 20, 2024
d4c6b1d
Merge branch 'develop' into tooling-dashboard/improve-asset-filter
panteleymonchuk Dec 20, 2024
8d81ff3
Merge remote-tracking branch 'origin/develop' into tooling-dashboard/…
panteleymonchuk Dec 23, 2024
57851fe
refactor(dashboard): adapt logic to useGetNFTs hook.
panteleymonchuk Dec 23, 2024
ea69c3d
feat(wallet-dashboard): add KioskTile component and integrate with As…
panteleymonchuk Dec 23, 2024
6565fd6
feat(dashboard): move KioskTile component to core and update references
panteleymonchuk Dec 23, 2024
bde631a
feat(dashboard): add KioskDetailsView and integrate with asset dialog…
panteleymonchuk Dec 23, 2024
81008ce
feat(core, wallet): move NftImage component to core and update refere…
panteleymonchuk Dec 23, 2024
4b710db
feat(dashboard): enhance AssetDialog and KioskDetailsView with select…
panteleymonchuk Dec 23, 2024
372e5af
Merge branch 'develop' into tooling-dashboard/improve-asset-filter
panteleymonchuk Dec 27, 2024
9e0acb8
Merge branch 'tooling-dashboard/improve-asset-filter' into tooling-da…
panteleymonchuk Jan 5, 2025
502121b
Merge remote-tracking branch 'origin/develop' into tooling-dashboard/…
panteleymonchuk Jan 8, 2025
170730c
fix(wallet-dashboard): improve asset loading logic and conditional re…
panteleymonchuk Jan 8, 2025
04c36ba
feat(wallet-dashboard): move logic for page to the hook
panteleymonchuk Jan 8, 2025
7e296af
Merge branch 'develop' into tooling-dashboard/improve-asset-filter
panteleymonchuk Jan 8, 2025
bc5f016
Merge remote-tracking branch 'origin/tooling-dashboard/improve-asset-…
panteleymonchuk Jan 8, 2025
75d9f28
Merge remote-tracking branch 'origin/develop' into tooling-dashboard/…
panteleymonchuk Jan 10, 2025
6910501
Merge remote-tracking branch 'origin/develop' into tooling-dashboard/…
panteleymonchuk Jan 13, 2025
175bc41
refactor(dashboard): add back button for kiosk item details, fix send…
panteleymonchuk Jan 13, 2025
4d0966c
Merge remote-tracking branch 'origin/develop' into tooling-dashboard/…
panteleymonchuk Jan 13, 2025
a962185
refactor(core): cleanup
panteleymonchuk Jan 14, 2025
e7c81ca
Merge branch 'develop' into tooling-dashboard/show-kiosk-in-the-dashb…
panteleymonchuk Jan 14, 2025
e137c1b
Merge branch 'develop' into tooling-dashboard/show-kiosk-in-the-dashb…
panteleymonchuk Jan 15, 2025
acda3a5
Merge branch 'develop' into tooling-dashboard/show-kiosk-in-the-dashb…
panteleymonchuk Jan 16, 2025
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
2 changes: 2 additions & 0 deletions apps/core/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ export * from './buttons';
export * from './collapsible';
export * from './providers';
export * from './stake';
export * from './kiosk';
export * from './nft';
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
import { getKioskIdFromOwnerCap, hasDisplayData, useGetKioskContents } from '@iota/core';
import { type IotaObjectResponse } from '@iota/iota-sdk/client';
import { useActiveAddress } from '_hooks';
import { ButtonUnstyled, CardImage, ImageType, truncate } from '@iota/apps-ui-kit';
import { getKioskIdFromOwnerCap, hasDisplayData, useGetKioskContents } from '../..';
import { type IotaObjectData, type IotaObjectResponse } from '@iota/iota-sdk/client';
import {
ButtonUnstyled,
CardImage,
ImageType,
truncate,
LoadingIndicator,
} from '@iota/apps-ui-kit';
import { PlaceholderReplace } from '@iota/ui-icons';

interface KioskProps {
object: IotaObjectResponse;
interface KioskTileProps {
object: IotaObjectResponse | IotaObjectData;
address?: string | null;
onClick?: () => void;
}

export function Kiosk({ object }: KioskProps) {
const address = useActiveAddress();
export function KioskTile({ object, address, onClick }: KioskTileProps) {
const { data: kioskData, isPending } = useGetKioskContents(address);

const kioskId = getKioskIdFromOwnerCap(object);
Expand All @@ -25,10 +31,18 @@ export function Kiosk({ object }: KioskProps) {
? null
: itemsWithDisplay[0].data?.display?.data?.image_url || null;

if (isPending) return null;
if (isPending)
return (
<div className="group relative aspect-square w-full cursor-pointer overflow-hidden rounded-xl flex items-center justify-center">
<LoadingIndicator />
</div>
);

return (
<div className="group relative aspect-square w-full cursor-pointer overflow-hidden rounded-xl">
<div
onClick={onClick}
className="group relative aspect-square w-full cursor-pointer overflow-hidden rounded-xl"
>
<div
className={
'group relative aspect-square w-full cursor-pointer overflow-hidden rounded-xl'
Expand Down
4 changes: 4 additions & 0 deletions apps/core/src/components/kiosk/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 './KioskTile';
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import { CardImage, ImageType, VisualAssetCard, VisualAssetType } from '@iota/apps-ui-kit';
import { PlaceholderReplace } from '@iota/ui-icons';
import cx from 'clsx';

export interface NftImageProps {
src: string | null;
Expand Down Expand Up @@ -33,7 +34,14 @@ export function NftImage({ src, title, isHoverable, video, icon, onIconClick }:
}
if (!imgSrc) {
return (
<div className="relative flex aspect-square h-full w-full items-center justify-center overflow-hidden rounded-xl">
<div
className={cx(
'relative flex aspect-square h-full w-full items-center justify-center overflow-hidden rounded-xl',
{
'group cursor-pointer': isHoverable,
},
)}
>
{isHoverable && (
<div className="absolute left-0 top-0 h-full w-full bg-cover bg-center bg-no-repeat group-hover:bg-shader-neutral-light-48 group-hover:transition group-hover:duration-300 group-hover:ease-in-out group-hover:dark:bg-shader-primary-dark-48" />
)}
Expand Down
4 changes: 4 additions & 0 deletions apps/core/src/components/nft/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 './NftImage';
1 change: 1 addition & 0 deletions apps/core/src/hooks/useTransferKioskItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function useTransferKioskItem({

return useMutation({
mutationFn: async ({ to }: { to: string }) => {
console.log('Transfering object', objectType, to);
panteleymonchuk marked this conversation as resolved.
Show resolved Hide resolved
if (!to || !executeFn || !objectType) {
throw new Error('Missing data');
}
Expand Down
66 changes: 57 additions & 9 deletions apps/wallet-dashboard/components/dialogs/assets/AssetDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ import { useState } from 'react';
import { Dialog } from '@iota/apps-ui-kit';
import { FormikProvider, useFormik } from 'formik';
import { useIotaClient, useCurrentAccount, useSignAndExecuteTransaction } from '@iota/dapp-kit';
import { createNftSendValidationSchema, useTransferAsset } from '@iota/core';
import { DetailsView, SendView } from './views';
import {
createNftSendValidationSchema,
useTransferAsset,
isKioskOwnerToken,
useKioskClient,
useNftDetails,
} from '@iota/core';
import { DetailsView, SendView, KioskDetailsView } from './views';
import { IotaObjectData, IotaTransactionBlockResponse } from '@iota/iota-sdk/client';
import { AssetsDialogView } from './constants';
import { TransactionDetailsView } from '../send-token';
Expand All @@ -28,17 +34,29 @@ const INITIAL_VALUES: FormValues = {
};

export function AssetDialog({ onClose, asset, refetchAssets }: AssetsDialogProps): JSX.Element {
const [view, setView] = useState<AssetsDialogView>(AssetsDialogView.Details);
const kioskClient = useKioskClient();
const account = useCurrentAccount();
const [digest, setDigest] = useState<string>('');
const activeAddress = account?.address ?? '';
const objectId = asset?.objectId ?? '';
const iotaClient = useIotaClient();
const validationSchema = createNftSendValidationSchema(activeAddress, objectId);
const { mutateAsync: signAndExecuteTransaction } =
useSignAndExecuteTransaction<IotaTransactionBlockResponse>();

const isTokenOwnedByKiosk = isKioskOwnerToken(kioskClient.network, asset);
const activeAddress = account?.address ?? '';

const initView = isTokenOwnedByKiosk ? AssetsDialogView.KioskDetails : AssetsDialogView.Details;

const [view, setView] = useState<AssetsDialogView>(initView);
const [chosenKioskAsset, setChoosenKioskAsset] = useState<IotaObjectData | null>(null);
const [digest, setDigest] = useState<string>('');

const activeAsset = chosenKioskAsset || asset;
const objectId = chosenKioskAsset ? chosenKioskAsset.objectId : asset ? asset.objectId : '';
const validationSchema = createNftSendValidationSchema(activeAddress, objectId);
const { objectData } = useNftDetails(objectId, activeAddress);

const { mutateAsync: sendAsset } = useTransferAsset({
objectId,
objectType: objectData?.type,
activeAddress: activeAddress,
executeFn: signAndExecuteTransaction,
});
Expand Down Expand Up @@ -76,19 +94,49 @@ export function AssetDialog({ onClose, asset, refetchAssets }: AssetsDialogProps
}
function onOpenChange() {
setView(AssetsDialogView.Details);
setChoosenKioskAsset(null);
onClose();
}

function onKioskItemClick(item: IotaObjectData) {
setChoosenKioskAsset(item);
setView(AssetsDialogView.Details);
}

function onBack() {
if (!chosenKioskAsset) {
return;
}
return () => {
setChoosenKioskAsset(null);
setView(AssetsDialogView.KioskDetails);
};
panteleymonchuk marked this conversation as resolved.
Show resolved Hide resolved
}

return (
<Dialog open onOpenChange={onOpenChange}>
<DialogLayout>
<>
{view === AssetsDialogView.KioskDetails && (
<KioskDetailsView
asset={activeAsset}
onClose={onOpenChange}
onItemClick={onKioskItemClick}
/>
)}
{view === AssetsDialogView.Details && (
<DetailsView asset={asset} onClose={onOpenChange} onSend={onDetailsSend} />
<DetailsView
asset={activeAsset}
onClose={onOpenChange}
onSend={onDetailsSend}
onBack={onBack()}
panteleymonchuk marked this conversation as resolved.
Show resolved Hide resolved
/>
)}
{view === AssetsDialogView.Send && (
<FormikProvider value={formik}>
<SendView
asset={asset}
objectId={objectId}
senderAddress={activeAddress}
onClose={onOpenChange}
onBack={onSendViewBack}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export enum AssetsDialogView {
Details = 'Details',
Send = 'Send',
TransactionDetails = 'TransactionDetails',
KioskDetails = 'KioskDetails',
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { ExplorerLinkType, useNftDetails, Collapsible, useNFTBasicData } from '@iota/core';
import {
Button,
ButtonType,
Header,
KeyValueInfo,
VisualAssetCard,
VisualAssetType,
} from '@iota/apps-ui-kit';
ExplorerLinkType,
useNftDetails,
Collapsible,
useNFTBasicData,
NftImage,
} from '@iota/core';
import { Button, ButtonType, Header, KeyValueInfo } from '@iota/apps-ui-kit';
import { formatAddress } from '@iota/iota-sdk/utils';
import { DialogLayoutBody, DialogLayoutFooter } from '../../layout';
import { IotaObjectData } from '@iota/iota-sdk/client';
Expand All @@ -20,9 +19,10 @@ interface DetailsViewProps {
asset: IotaObjectData;
onClose: () => void;
onSend: () => void;
onBack?: () => void;
}

export function DetailsView({ onClose, asset, onSend }: DetailsViewProps) {
export function DetailsView({ onClose, asset, onSend, onBack }: DetailsViewProps) {
const account = useCurrentAccount();

const senderAddress = account?.address ?? '';
Expand Down Expand Up @@ -53,17 +53,11 @@ export function DetailsView({ onClose, asset, onSend }: DetailsViewProps) {

return (
<>
<Header title="Asset" onClose={onClose} titleCentered />
<Header title="Asset" onClose={onClose} titleCentered onBack={onBack} />
<DialogLayoutBody>
<div className="flex w-full flex-col items-center justify-center gap-xs">
<div className="w-[172px]">
<VisualAssetCard
assetSrc={nftImageUrl}
assetTitle={nftName}
assetType={VisualAssetType.Image}
altText={nftName || 'NFT'}
isHoverable={false}
/>
<NftImage src={nftImageUrl} title={nftName || 'NFT'} isHoverable={false} />
</div>
<ExplorerLink type={ExplorerLinkType.Object} objectID={objectId}>
<Button type={ButtonType.Ghost} text="View on Explorer" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import {
useGetKioskContents,
getKioskIdFromOwnerCap,
useNftDetails,
NftImage,
Collapsible,
ExplorerLinkType,
} from '@iota/core';
import { Header, KeyValueInfo, LoadingIndicator } from '@iota/apps-ui-kit';
import { DialogLayoutBody, DialogLayoutFooter } from '../../layout';
import { IotaObjectData } from '@iota/iota-sdk/client';
import { useCurrentAccount } from '@iota/dapp-kit';
import { ExplorerLink } from '@/components/ExplorerLink';
import { formatAddress } from '@iota/iota-sdk/utils';

interface DetailsViewProps {
asset: IotaObjectData;
onClose: () => void;
onItemClick: (asset: IotaObjectData) => void;
}

export function KioskDetailsView({ onClose, asset, onItemClick }: DetailsViewProps) {
cpl121 marked this conversation as resolved.
Show resolved Hide resolved
const account = useCurrentAccount();
const senderAddress = account?.address ?? '';
const objectId = getKioskIdFromOwnerCap(asset);
const { data: kioskData, isPending } = useGetKioskContents(account?.address);
const kiosk = kioskData?.kiosks.get(objectId);
const items = kiosk?.items;

if (isPending) {
return (
<div className="flex h-full items-center justify-center">
<LoadingIndicator />
</div>
);
}

return (
<>
<Header title="Kiosk" onClose={onClose} titleCentered />
<DialogLayoutBody>
<div className="mb-auto grid grid-cols-3 items-center justify-center gap-3">
{items?.map((item) => {
return item.data?.objectId ? (
<div
onClick={() => {
item.data && onItemClick(item.data);
}}
key={item.data?.objectId}
>
<KioskItem object={item.data} address={senderAddress} />
</div>
) : null;
})}
</div>
</DialogLayoutBody>
<DialogLayoutFooter>
<Collapsible defaultOpen title="Details">
<div className="flex flex-col gap-y-sm px-md py-xs">
<KeyValueInfo
keyText="Number of Items"
value={items?.length || '0'}
fullwidth
/>
<KeyValueInfo
keyText="Kiosk ID"
value={
<ExplorerLink objectID={objectId!} type={ExplorerLinkType.Object}>
{formatAddress(objectId!)}
</ExplorerLink>
}
fullwidth
/>
</div>
</Collapsible>
</DialogLayoutFooter>
</>
);
}

interface KioskItemProps {
object: IotaObjectData;
address: string;
}

function KioskItem({ object, address }: KioskItemProps) {
const { nftName, nftImageUrl } = useNftDetails(object.objectId, address);

return <NftImage title={nftName} src={nftImageUrl} isHoverable />;
}
Loading
Loading