Skip to content

Commit 53c5718

Browse files
committed
add useDahGallery
1 parent d962311 commit 53c5718

File tree

5 files changed

+297
-0
lines changed

5 files changed

+297
-0
lines changed

src/composables/useDahGallery.js

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import { ref, onMounted, watch } from 'vue';
2+
import { useEvmNft } from './useEvmNft';
3+
import { useNftStore } from '../stores/nftStore';
4+
import { ethers } from 'ethers';
5+
6+
/**
7+
* Similar to the useEvmMetaDataGallery but this composable is designed to fetch
8+
* NFT meta data with much less on-chain validation. This allows for faster
9+
* fetching, and larger page sizes, including the ability to fetch all NFTs
10+
* in one query. This composable cannot fetch NFTs from a specific wallet,
11+
* and is designed only to fetch all NFTs on a contract. This requires the
12+
* developer to provide a contract supply and start token ID because we will
13+
* not look on-chain for this data using this method.
14+
* @param {object} config - The DahMetaDataOptions configuration object for
15+
* the useDahGallery.
16+
* @returns page, numberOfPages, nfts, isAscending, toggleSortOrder,
17+
* isLoading loadingMessage, getNftPage, getTokenOwner, getTokenMetaData.
18+
*/
19+
export function useDahGallery(config) {
20+
const {
21+
contractPublicKey,
22+
contractAddress,
23+
abi,
24+
chainId,
25+
rpc,
26+
itemsPerPage,
27+
nftStoreItemCollectionName,
28+
isAscendingSort,
29+
isGetAllNftQuery,
30+
startTokenId,
31+
supply,
32+
} = config;
33+
34+
const holderPublicKey = null;
35+
const nftStore = useNftStore();
36+
37+
const page = ref(1);
38+
const numberOfPages = ref(0);
39+
const nfts = ref([]);
40+
const isAscending = ref(isAscendingSort);
41+
const isLoading = ref(false);
42+
const loadingMessage = ref('');
43+
44+
// Proxy functions from useEvmNft.
45+
let _getMyNfts = null;
46+
let _getTokenOwner = null;
47+
let _getTokenMetaData = null;
48+
49+
onMounted(async () => {
50+
nftStore.addCollection(nftStoreItemCollectionName);
51+
52+
const evmNft = await useEvmNft(
53+
parseInt(itemsPerPage),
54+
new ethers.JsonRpcProvider(rpc),
55+
holderPublicKey,
56+
contractPublicKey,
57+
contractAddress,
58+
abi,
59+
chainId
60+
);
61+
62+
loadingMessage.value = evmNft.loadingMessage; // bind ref to loadingMessage
63+
64+
// Set the function pointer for calling later, after mount.
65+
_getMyNfts = evmNft.getDahCollection;
66+
_getTokenOwner = evmNft.getTokenOwner;
67+
_getTokenMetaData = evmNft.getTokenMetaData;
68+
69+
if (isGetAllNftQuery) {
70+
await getAllNfts();
71+
} else {
72+
await getNftPage(page.value);
73+
}
74+
});
75+
76+
// Get NFTs if page changes.
77+
watch(page, async (newPage, oldPage) => {
78+
if (newPage !== oldPage) {
79+
await getNftPage(newPage);
80+
}
81+
});
82+
83+
/**
84+
* Toggles the sort order of the NFTs between ascending and descending.
85+
* It also clears the current collection and resets pagination to the first page.
86+
* @returns {Promise<void>} - A promise for a page of NFTs
87+
*/
88+
async function toggleSortOrder() {
89+
isAscending.value = !isAscending.value;
90+
nftStore.itemCollections[nftStoreItemCollectionName].items = [];
91+
nftStore.itemCollections[nftStoreItemCollectionName].page = 1;
92+
page.value = 1;
93+
await getNftPage(page.value);
94+
}
95+
96+
/**
97+
* Fetches a specific page of NFTs and associated metadata.
98+
* This function updates the local state with NFTs and their pagination details.
99+
* @param {number} iPage - The page number to retrieve.
100+
* @returns - A promise that resolves once the NFTs are fetched.
101+
*/
102+
async function getNftPage(iPage) {
103+
try {
104+
isLoading.value = true;
105+
// Skip fetching NFTs if we already have them.
106+
if (
107+
nftStore.itemCollections[nftStoreItemCollectionName].items[iPage - 1]
108+
) {
109+
nfts.value =
110+
nftStore.itemCollections[nftStoreItemCollectionName].items[iPage - 1];
111+
numberOfPages.value =
112+
nftStore.itemCollections[nftStoreItemCollectionName].page;
113+
return;
114+
}
115+
116+
// calling getDahCollection here...
117+
const { tokens, pageSize, count } = await _getMyNfts(
118+
iPage,
119+
isAscending.value,
120+
supply,
121+
startTokenId
122+
);
123+
// append tokens if isGetAllNftQuery is true
124+
if (isGetAllNftQuery) {
125+
nfts.value = nfts.value.concat(tokens);
126+
} else {
127+
nfts.value = tokens;
128+
}
129+
130+
nftStore.setCollectionItems(
131+
iPage,
132+
nfts.value, // used to be tokens, just need the appended items
133+
nftStoreItemCollectionName
134+
);
135+
nftStore.itemCollections[nftStoreItemCollectionName].page = Math.ceil(
136+
count / pageSize
137+
);
138+
numberOfPages.value =
139+
nftStore.itemCollections[nftStoreItemCollectionName].page;
140+
nftStore.itemCollections[nftStoreItemCollectionName].itemCount = count;
141+
} catch (error) {
142+
console.error('Error in getNftPage:', error);
143+
throw error;
144+
} finally {
145+
isLoading.value = false;
146+
}
147+
}
148+
149+
/**
150+
* Fetches all NFTs and associated metadata for a given contract in a loop
151+
* with no paging.
152+
*/
153+
async function getAllNfts() {
154+
try {
155+
isLoading.value = true;
156+
await getNftPage(1);
157+
for (let i = 2; i <= numberOfPages.value; i++) {
158+
await getNftPage(i);
159+
}
160+
} catch (error) {
161+
console.error('Error in getAllNfts:', error);
162+
throw error;
163+
} finally {
164+
isLoading.value = false;
165+
}
166+
}
167+
168+
/**
169+
* Fetches the owner of a specific token by its ID. Exposing a proxy function for evmNft.
170+
* @param {number} tokenId - The ID of the token to look up the owner for.
171+
* @returns {Promise<string>} - A promise that resolves with the owner’s address.
172+
*/
173+
async function getTokenOwner(tokenId) {
174+
return await _getTokenOwner(tokenId);
175+
}
176+
177+
/**
178+
* Retrieves metadata for a given set of token IDs. Exposing a proxy function for evmNft.
179+
* @param {array} tokenIds - An array of token IDs to retrieve metadata for.
180+
* @returns {Promise<object>} - A promise that resolves with the metadata for the tokens.
181+
*/
182+
async function getTokenMetaData(tokenIds) {
183+
return await _getTokenMetaData(tokenIds);
184+
}
185+
186+
return {
187+
page,
188+
numberOfPages,
189+
nfts,
190+
isAscending,
191+
isLoading,
192+
loadingMessage,
193+
toggleSortOrder,
194+
getNftPage,
195+
getTokenOwner,
196+
getTokenMetaData,
197+
};
198+
}

src/composables/useEvmNft.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,11 +450,65 @@ export async function useEvmNft(
450450
return { tokens, pageSize, count: _balance.value };
451451
}
452452

453+
/**
454+
* Retrieves and paginates NFT metadata based on a provided (cached)
455+
* token balance. This method optimizes performance by avoiding direct
456+
* blockchain queries for token IDs, instead calculating them directly.
457+
* If a chain ID is specified, this function will be extra fast because
458+
* it can use Dig-A-Hash predictable meta data.
459+
* @param {number} page - The page number for pagination. Defaults to 1 if not provided.
460+
* @param {boolean} isAscending - If true, sorts tokens in ascending order by token ID; if false, descending order.
461+
* @param {number} contractBalance - The number of NFTs on the contract.
462+
* @param {number} contractStartTokenId - 1 or 0, the starting token ID.
463+
* @returns {Promise<Object>} An object containing: {Array} tokens - An array of objects where each object includes token metadata, and token ID.
464+
* - {number} pageSize - The size of each page (number of items per page).
465+
* - {number} count - The total number of tokens or NFTs for the specified contract.
466+
* @throws {Error} If the contract instance has not been initialized.
467+
*/
468+
async function getDahCollection(
469+
page,
470+
isAscending,
471+
contractBalance,
472+
contractStartTokenId
473+
) {
474+
_contractRequired();
475+
loadingMessage.value = 'Connecting to CDN...';
476+
477+
_startTokenId.value = contractStartTokenId;
478+
_balance.value = contractBalance;
479+
480+
if (_balance.value === 0) {
481+
return { tokens: [], pageSize, count: 0 };
482+
}
483+
484+
const { startIndex, endIndex, lastPage } = _calculatePageIndexes(
485+
page,
486+
isAscending
487+
);
488+
489+
const tokenIds = [];
490+
for (let i = startIndex; i <= endIndex; i++) {
491+
tokenIds.push(i);
492+
}
493+
494+
const tokens = await getTokenMetaData(tokenIds);
495+
496+
// Ensure we sort
497+
if (isAscending) {
498+
tokens.sort((a, b) => a.tokenId - b.tokenId);
499+
} else {
500+
tokens.sort((a, b) => b.tokenId - a.tokenId);
501+
}
502+
503+
return { tokens, pageSize, count: _balance.value };
504+
}
505+
453506
return {
454507
getNfts,
455508
getTokenOwner,
456509
getTokenMetaData,
457510
loadingMessage,
458511
getMetaDataCollection,
512+
getDahCollection,
459513
};
460514
}

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './stores/nftStore.js';
22
export * from './composables/useEvmNft.js';
33
export * from './composables/useEvmNftGallery.js';
44
export * from './composables/useEvmMetaDataGallery.js';
5+
export * from './composables/useDahGallery.js';
56
export * from './modules/blockchains.js';
67
export * from './modules/dahDemoV1Abi.js';
78
export * from './modules/dahNftV2Abi.js';

src/types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './useEvmNft';
22
export * from './useEvmNftGallery';
3+
export * from './useDahGallery';
34
export * from './useEvmMetaDataGallery';
45
export * from './useNftStore';
56
export * from './blockchains';

src/types/useDahGallery.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { type ref, Ref } from 'vue';
2+
import { type Nft } from './useNftStore';
3+
4+
/**
5+
* The DahGalleryOptions configuration object for the useDahGallery composable.
6+
*/
7+
export interface DahGalleryOptions {
8+
contractPublicKey: string;
9+
contractAddress: string;
10+
abi: any[];
11+
chainId: number | null;
12+
rpc: string;
13+
itemsPerPage: number;
14+
nftStoreItemCollectionName: string;
15+
isAscendingSort: boolean;
16+
isGetAllNftQuery: boolean;
17+
startTokenId: number;
18+
supply: number;
19+
}
20+
21+
/**
22+
* Similar to the useEvmNftGallery but this composable is designed to fetch
23+
* NFT meta data with much less on-chain validation. This allows for faster
24+
* fetching, and larger page sizes, including the ability to fetch all NFTs
25+
* in one query. This composable cannot fetch NFTs from a specific wallet,
26+
* and is designed only to fetch all NFTs on a contract.
27+
* @param {object} config - The EvmMetaDataOptions configuration object for
28+
* the useEvmMetaDataGallery.
29+
* @returns page, numberOfPages, nfts, isAscending, toggleSortOrder,
30+
* isLoading loadingMessage, getNftPage, getTokenOwner, getTokenMetaData.
31+
*/
32+
export declare function useDahGallery(config: DahGalleryOptions): {
33+
page: Ref<number>;
34+
numberOfPages: Ref<number>;
35+
nfts: Ref<Nft[]>;
36+
isAscending: Ref<boolean>;
37+
isLoading: Ref<boolean>;
38+
loadingMessage: Ref<string>;
39+
toggleSortOrder: () => Promise<void>;
40+
getNftPage: (iPage: number) => Promise<void>;
41+
getTokenOwner: (tokenId: number) => Promise<string>;
42+
getTokenMetaData: (tokenIds: number[]) => Promise<Nft[]>;
43+
};

0 commit comments

Comments
 (0)