@@ -35,23 +33,25 @@
{localize('views.collectibles.collectionsGallery.title')}
- {String(queriedCollections.length ?? '')}
+ {String(Object.keys($selectedAccountCollections).length ?? '')}
- {#if collections.length}
-
-
+ {#if hasCollections}
+
{/if}
{#if features.collectibles.erc721.enabled}
{/if}
- {#if collections.length}
- {#if queriedCollections.length}
+ {#if hasCollections}
+ {#if Object.keys(queriedCollections).length > 0}
+ {#each Object.keys(queriedCollections) as collection}
+ {queriedCollections[collection].name}
+ {/each}
{:else}
= writable({})
+
+async function updateCollections(nfts: Nft[]): Promise {
+ const existingCollections = get(collectionsStore)
+
+ if (nfts.length === 0) {
+ if (Object.keys(existingCollections).length > 0) {
+ collectionsStore.set({})
+ }
+ return
+ }
+
+ const collectionsUpdate = { ...existingCollections }
+
+ await Promise.all(
+ nfts.map(async (nft) => {
+ if (nft.standard !== NftStandard.Irc27 || !nft.issuer) {
+ return
+ }
+
+ const issuerId = nft.issuer.aliasId ?? nft.issuer.nftId
+ if (!issuerId) {
+ return
+ }
+
+ if (!collectionsUpdate[issuerId]) {
+ const collection = await getCollectionFromNft(nft)
+ if (collection) {
+ collectionsUpdate[issuerId] = { ...collection, nfts: [nft] }
+ }
+ } else {
+ const existingNfts = collectionsUpdate[issuerId].nfts
+ if (!existingNfts.find((existingNft) => existingNft.id === nft.id)) {
+ collectionsUpdate[issuerId].nfts.push(nft)
+ }
+ }
+ })
+ )
+ collectionsStore.set(collectionsUpdate)
+}
+
+selectedAccountNfts.subscribe((nfts) => {
+ void updateCollections(nfts)
+})
+
+export const selectedAccountCollections: Readable = derived(
+ collectionsStore,
+ ($collectionsStore) => $collectionsStore
+)
+
+export const collectionsSearchTerm: Writable = writable('')
diff --git a/packages/shared/src/lib/core/nfts/types/collections.type.ts b/packages/shared/src/lib/core/nfts/types/collections.type.ts
new file mode 100644
index 0000000000..32dae6f7df
--- /dev/null
+++ b/packages/shared/src/lib/core/nfts/types/collections.type.ts
@@ -0,0 +1,3 @@
+import { Collection } from '../interfaces'
+
+export type Collections = { [key: string]: Collection }
diff --git a/packages/shared/src/lib/core/nfts/types/index.ts b/packages/shared/src/lib/core/nfts/types/index.ts
index 3d34a70382..77e3cbecb6 100644
--- a/packages/shared/src/lib/core/nfts/types/index.ts
+++ b/packages/shared/src/lib/core/nfts/types/index.ts
@@ -1,2 +1,3 @@
+export * from './collections.type'
export * from './nft-download-options.type'
export * from './persisted-nft.type'
diff --git a/packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts b/packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts
new file mode 100644
index 0000000000..232f4d632e
--- /dev/null
+++ b/packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts
@@ -0,0 +1,42 @@
+import { NftStandard } from '../enums'
+import { Collection, Nft } from '../interfaces'
+import { Converter } from '@core/utils'
+import { getClient } from '@core/profile-manager'
+import type { AliasOutput, MetadataFeature, NftOutput } from '@iota/sdk'
+import { FeatureType } from '@iota/sdk/out/types'
+
+export async function getCollectionFromNft(nft: Nft): Promise {
+ if (nft.standard !== NftStandard.Irc27) {
+ return
+ }
+
+ const { aliasId = '', nftId = '' } = nft.issuer ?? {}
+ if (!aliasId && !nftId) {
+ return
+ }
+
+ try {
+ const client = await getClient()
+ const outputId = aliasId ? await client.aliasOutputId(aliasId) : await client.nftOutputId(nftId)
+ if (!outputId) {
+ return
+ }
+
+ const outputResponse = await client.getOutput(outputId)
+ const output = outputResponse.output as AliasOutput | NftOutput
+
+ const metadataFeature = output.immutableFeatures?.find(
+ (feature) => feature.type === FeatureType.Metadata
+ ) as MetadataFeature
+
+ if (!metadataFeature?.data) {
+ return
+ }
+
+ const { standard, name, type, uri } = JSON.parse(Converter.hexToUtf8(metadataFeature.data))
+
+ return { standard, name, type, uri, nfts: [] }
+ } catch (error) {
+ console.error('Error retrieving collection from NFT:', error)
+ }
+}
diff --git a/packages/shared/src/lib/core/nfts/utils/index.ts b/packages/shared/src/lib/core/nfts/utils/index.ts
index 93e479f6d5..f8305f6b34 100644
--- a/packages/shared/src/lib/core/nfts/utils/index.ts
+++ b/packages/shared/src/lib/core/nfts/utils/index.ts
@@ -1,17 +1,19 @@
export * from './buildNftFromPersistedErc721Nft'
+export * from './buildPersistedErc721Nft'
export * from './checkIfNftShouldBeDownloaded'
+export * from './fetchWithTimeout'
+export * from './getCollectionFromNft'
+export * from './getFetchableNftUrls'
export * from './getFilePathForNft'
export * from './getNftsFromNftIds'
export * from './getOwnerOfErc721Nft'
-export * from './buildPersistedErc721Nft'
-export * from './getFetchableNftUrls'
export * from './getPrimaryNftUrl'
export * from './getSpendableStatusFromUnspentNftOutput'
-export * from './fetchWithTimeout'
export * from './isIrc27Nft'
-export * from './isNftOwnedByAnyAccount'
export * from './isNftLocked'
+export * from './isNftOwnedByAnyAccount'
export * from './isScamIrc27Nft'
export * from './isValidNftUri'
+export * from './isVisibleCollection'
export * from './isVisibleNft'
export * from './parseNftMetadata'
diff --git a/packages/shared/src/lib/core/nfts/utils/isVisibleCollection.ts b/packages/shared/src/lib/core/nfts/utils/isVisibleCollection.ts
new file mode 100644
index 0000000000..6c367e4cbd
--- /dev/null
+++ b/packages/shared/src/lib/core/nfts/utils/isVisibleCollection.ts
@@ -0,0 +1,20 @@
+import { get } from 'svelte/store'
+import { collectionsSearchTerm } from '../stores'
+import { Collection } from '../interfaces'
+
+export function isVisibleCollection(collection: Collection): boolean {
+ const searchTerm = get(collectionsSearchTerm)
+
+ if (!isVisibleWithSearchTerm(collection, searchTerm)) {
+ return false
+ }
+
+ return true
+}
+
+function isVisibleWithSearchTerm(collection: Collection, searchTerm: string): boolean {
+ if (searchTerm) {
+ return collection.name.toLowerCase().includes(searchTerm.toLowerCase())
+ }
+ return true
+}