From 901f265e6c9fc39c77c328871ccdab85fecbf006 Mon Sep 17 00:00:00 2001 From: "Ng Wing Tat, David" Date: Sat, 26 Nov 2022 00:47:35 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E2=9C=A8=20[NFT=20Details]=20Override=20NF?= =?UTF-8?q?T=20Class=20metadata=20with=20NFT=20metadata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mixins/nft.js | 4 +- src/mixins/portfolio.js | 4 +- src/pages/nft/class/_classId/_nftId.vue | 50 ++++++++++++++++++------- src/pages/nft/class/_classId/index.vue | 2 +- src/store/modules/nft.js | 29 +++++++++++++- src/util/api/index.js | 5 ++- 6 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/mixins/nft.js b/src/mixins/nft.js index 7e0575fb1..5e8ea4c4d 100644 --- a/src/mixins/nft.js +++ b/src/mixins/nft.js @@ -321,7 +321,7 @@ export default { ...mapActions([ 'lazyGetUserInfoByAddress', 'fetchNFTPurchaseInfo', - 'fetchNFTMetadata', + 'fetchNFTClassMetadata', 'fetchNFTOwners', 'initIfNecessary', 'uiToggleCollectModal', @@ -344,7 +344,7 @@ export default { }, async updateNFTClassMetadata() { try { - await this.fetchNFTMetadata(this.classId); + await this.fetchNFTClassMetadata(this.classId); } catch (error) { if (error.response?.status !== 404) { // eslint-disable-next-line no-console diff --git a/src/mixins/portfolio.js b/src/mixins/portfolio.js index 9e36885eb..dcf3b2d34 100644 --- a/src/mixins/portfolio.js +++ b/src/mixins/portfolio.js @@ -268,7 +268,7 @@ export default { methods: { ...mapActions([ 'fetchNFTListByAddress', - 'fetchNFTMetadata', + 'fetchNFTClassMetadata', 'fetchNFTPurchaseInfo', 'fetchNFTOwners', ]), @@ -318,7 +318,7 @@ export default { async fetchNFTClassInfo(classId) { let metadata; try { - metadata = await this.fetchNFTMetadata(classId); + metadata = await this.fetchNFTClassMetadata(classId); } catch (error) { if (error.response?.status !== 404) { // eslint-disable-next-line no-console diff --git a/src/pages/nft/class/_classId/_nftId.vue b/src/pages/nft/class/_classId/_nftId.vue index 71a1501fb..f8059ba0e 100644 --- a/src/pages/nft/class/_classId/_nftId.vue +++ b/src/pages/nft/class/_classId/_nftId.vue @@ -97,17 +97,17 @@ :is-writing-nft="nftIsWritingNFT" > to change only, please use `this.nftId` instead selectedNFTId: this.$route.params.nftId, isLoading: true, @@ -292,6 +293,25 @@ export default { nftId() { return this.$route.params.nftId; }, + nftExternalURL() { + return this.nftMetadata.external_url || this.NFTExternalUrl; + }, + nftImageBackgroundColor() { + return this.nftMetadata.background_color || this.NFTImageBackgroundColor; + }, + nftImageURL() { + const image = this.nftMetadata.image || this.NFTImageUrl; + const [schema, path] = image.split('://'); + if (schema === 'ar') return `${ARWEAVE_ENDPOINT}/${path}`; + if (schema === 'ipfs') return `${IPFS_VIEW_GATEWAY_URL}/${path}`; + return image; + }, + nftName() { + return this.nftMetadata.name || this.NFTName; + }, + nftDescription() { + return this.nftMetadata.description || this.NFTDescription; + }, isTransferDisabled() { return this.isOwnerInfoLoading || !this.userCollectedCount; }, @@ -318,12 +338,9 @@ export default { })); }, }, - asyncData({ query }) { + async asyncData({ route, query, store, redirect, error }) { const { action } = query; - return { action }; - }, - async fetch({ route, store, redirect, error }) { - const { classId } = route.params; + const { classId, nftId } = route.params; const { referrer } = route.query; if (referrer) { redirect({ @@ -331,11 +348,12 @@ export default { params: { classId }, query: { referrer }, }); - return; + return undefined; } + let nftMetadata; try { await Promise.all([ - store.dispatch('fetchNFTMetadata', classId), + store.dispatch('fetchNFTClassMetadata', classId), store.dispatch('lazyGetNFTPurchaseInfo', classId).catch(err => { if (err.response?.data !== 'NFT_CLASS_NOT_FOUND') { // eslint-disable-next-line no-console @@ -343,6 +361,10 @@ export default { } }), ]); + nftMetadata = await store.dispatch('fetchNFTMetadata', { + classId, + nftId, + }); } catch (err) { if (err.response?.data?.code === 3) { error({ @@ -357,7 +379,9 @@ export default { message: 'NFT_FETCH_ERROR', }); } + return undefined; } + return { nftMetadata, action }; }, async mounted() { try { @@ -390,7 +414,7 @@ export default { } }, methods: { - ...mapActions(['lazyFetchLIKEPrice']), + ...mapActions(['lazyFetchLIKEPrice', 'fetchNFTMetadata']), onSelectNFT(e) { const { value: nftId } = e.target; logTrackerEvent(this, 'NFT', 'nft_details_select_nft', nftId, 1); diff --git a/src/pages/nft/class/_classId/index.vue b/src/pages/nft/class/_classId/index.vue index 87912d9ed..30afb37bd 100644 --- a/src/pages/nft/class/_classId/index.vue +++ b/src/pages/nft/class/_classId/index.vue @@ -231,7 +231,7 @@ export default { } try { await Promise.all([ - store.dispatch('fetchNFTMetadata', classId), + store.dispatch('fetchNFTClassMetadata', classId), store.dispatch('lazyGetNFTPurchaseInfo', classId).catch(err => { if (err.response?.data !== 'NFT_CLASS_NOT_FOUND') { // eslint-disable-next-line no-console diff --git a/src/store/modules/nft.js b/src/store/modules/nft.js index 1822ed9d7..56f231511 100644 --- a/src/store/modules/nft.js +++ b/src/store/modules/nft.js @@ -162,13 +162,13 @@ const actions = { } return info; }, - async fetchNFTMetadata({ commit }, classId) { + async fetchNFTClassMetadata({ commit }, classId) { let metadata; /* HACK: Use restful API instead of cosmjs to avoid loading libsodium, which is huge and affects index page performance */ // const chainMetadata = await getClassInfo(classId); const { class: chainMetadata } = await this.$api.$get( - api.getNFTClassMetadata(classId) + api.getChainNFTClassMetadataEndpoint(classId) ); const { name, @@ -219,6 +219,31 @@ const actions = { commit(TYPES.NFT_SET_NFT_CLASS_METADATA, { classId, metadata }); return metadata; }, + async fetchNFTMetadata({ state }, { classId, nftId }) { + const classData = state.metadataByClassIdMap[classId]; + const classMetadata = classData.metadata || {}; + let metadata; + const { nft: chainMetadata } = await this.$api.$get( + api.getChainNFTMetadataEndpoint(classId, nftId) + ); + const { uri, data: { metadata: nftMetadata = {} } = {} } = + chainMetadata || {}; + metadata = { + uri, + ...classMetadata, + ...nftMetadata, + }; + if (isValidHttpUrl(uri)) { + const apiMetadata = await this.$api.$get(uri).catch(err => { + if (!err.response?.status === 404) { + // eslint-disable-next-line no-console + console.error(err); + } + }); + if (apiMetadata) metadata = { ...metadata, ...apiMetadata }; + } + return metadata; + }, async fetchNFTOwners({ commit }, classId) { const { owners } = await this.$api.$get(api.getNFTOwners(classId)); const info = formatOwnerInfoFromChain(owners); diff --git a/src/util/api/index.js b/src/util/api/index.js index 9a05281de..211221c57 100644 --- a/src/util/api/index.js +++ b/src/util/api/index.js @@ -135,9 +135,12 @@ export const getChainExplorerTx = hash => `${LIKECOIN_CHAIN_VIEW_TX}/${hash}`; export const getChainRawTx = hash => `${LIKECOIN_CHAIN_API}/cosmos/tx/v1beta1/txs/${hash}`; -export const getNFTClassMetadata = classId => +export const getChainNFTClassMetadataEndpoint = classId => `${LIKECOIN_CHAIN_API}/cosmos/nft/v1beta1/classes/${classId}`; +export const getChainNFTMetadataEndpoint = (classId, nftId) => + `${LIKECOIN_CHAIN_API}/cosmos/nft/v1beta1/nfts/${classId}/${nftId}`; + export const getISCNRecord = iscnId => { const qsPayload = { iscn_id: iscnId, From 20ff2a501b5535ef4f9426c25ed8abce456ff7e3 Mon Sep 17 00:00:00 2001 From: "Ng Wing Tat, David" Date: Sat, 26 Nov 2022 00:48:29 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=94=87=20Remove=20404=20error=20loggi?= =?UTF-8?q?ng?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/modules/nft.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/store/modules/nft.js b/src/store/modules/nft.js index 56f231511..69f19f9dd 100644 --- a/src/store/modules/nft.js +++ b/src/store/modules/nft.js @@ -185,18 +185,24 @@ const actions = { iscn_id: iscnId, }; if (isValidHttpUrl(uri)) { - const apiMetadata = await this.$api - .$get(uri) - // eslint-disable-next-line no-console - .catch(err => console.error(err)); + const apiMetadata = await this.$api.$get(uri).catch(err => { + if (!err.response?.status === 404) { + // eslint-disable-next-line no-console + console.error(err); + } + }); if (apiMetadata) metadata = { ...metadata, ...apiMetadata }; } if (!(metadata.iscn_owner || metadata.account_owner)) { if (iscnId) { const iscnRecord = await this.$api .$get(api.getISCNRecord(iscnId)) - // eslint-disable-next-line no-console - .catch(err => console.error(err)); + .catch(err => { + if (!err.response?.status === 404) { + // eslint-disable-next-line no-console + console.error(err); + } + }); const iscnOwner = iscnRecord?.owner; const iscnRecordTimestamp = iscnRecord?.records?.[0]?.recordTimestamp; if (iscnOwner) From c5dca0c68de413fbedf594610f86cf2cb8952f7c Mon Sep 17 00:00:00 2001 From: "Ng Wing Tat, David" Date: Sat, 26 Nov 2022 11:45:16 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=8E=A8=20Store=20NFT=20metadata=20in?= =?UTF-8?q?=20VueX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mixins/nft.js | 28 +++++++++++++++----- src/pages/nft/class/_classId/_nftId.vue | 34 ++++--------------------- src/store/modules/nft.js | 11 +++++--- src/store/mutation-types.js | 1 + src/util/nft.js | 9 +++++++ 5 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/mixins/nft.js b/src/mixins/nft.js index 5e8ea4c4d..6ff38e67c 100644 --- a/src/mixins/nft.js +++ b/src/mixins/nft.js @@ -5,8 +5,6 @@ import { CrispMixinFactory } from '~/mixins/crisp'; import { APP_LIKE_CO_VIEW, APP_LIKE_CO_URL_BASE, - ARWEAVE_ENDPOINT, - IPFS_VIEW_GATEWAY_URL, TX_STATUS, LIKECOIN_NFT_API_WALLET, LIKECOIN_NFT_COLLECT_WITHOUT_WALLET_ITEMS_BY_CREATORS, @@ -32,6 +30,7 @@ import { getISCNRecord, getNFTClassCollectionType, formatNFTEventsToHistory, + parseNFTMetadataURL, } from '~/util/nft'; import { formatNumberWithUnit, formatNumberWithLIKE } from '~/util/ui'; @@ -99,6 +98,7 @@ export default { 'getNFTClassOwnerInfoById', 'getNFTClassOwnerCount', 'getNFTClassCollectedCount', + 'getNFTMetadataById', 'LIKEPriceInUSD', 'uiIsOpenCollectModal', 'uiTxTargetClassId', @@ -107,6 +107,9 @@ export default { NFTClassMetadata() { return this.getNFTClassMetadataById(this.classId) || {}; }, + nftMetadata() { + return this.getNFTMetadataById(this.nftId) || {}; + }, nftClassCollectionType() { return getNFTClassCollectionType(this.NFTClassMetadata); }, @@ -134,22 +137,35 @@ export default { NFTName() { return this.NFTClassMetadata.name; }, + nftName() { + return this.nftMetadata.name || this.NFTName; + }, NFTDescription() { return this.NFTClassMetadata.description; }, + nftDescription() { + return this.nftMetadata.description || this.NFTDescription; + }, NFTImageUrl() { const { image = '' } = this.NFTClassMetadata; - const [schema, path] = image.split('://'); - if (schema === 'ar') return `${ARWEAVE_ENDPOINT}/${path}`; - if (schema === 'ipfs') return `${IPFS_VIEW_GATEWAY_URL}/${path}`; - return this.NFTClassMetadata.image; + return parseNFTMetadataURL(image); + }, + nftImageURL() { + const image = this.nftMetadata.image || this.NFTImageUrl; + return parseNFTMetadataURL(image); }, NFTImageBackgroundColor() { return this.NFTClassMetadata.background_color; }, + nftImageBackgroundColor() { + return this.nftMetadata.background_color || this.NFTImageBackgroundColor; + }, NFTExternalUrl() { return this.NFTClassMetadata.external_url; }, + nftExternalURL() { + return this.nftMetadata.external_url || this.NFTExternalUrl; + }, NFTPrice() { return this.purchaseInfo.price; }, diff --git a/src/pages/nft/class/_classId/_nftId.vue b/src/pages/nft/class/_classId/_nftId.vue index f8059ba0e..63fb50321 100644 --- a/src/pages/nft/class/_classId/_nftId.vue +++ b/src/pages/nft/class/_classId/_nftId.vue @@ -211,11 +211,11 @@ export default { }, mixins: [clipboardMixin, nftMixin, navigationListenerMixin], head() { - const title = this.NFTName || this.$t('nft_details_page_title'); + const title = this.nftName || this.$t('nft_details_page_title'); const description = - this.NFTDescription || this.$t('nft_details_page_description'); + this.nftDescription || this.$t('nft_details_page_description'); const ogImage = - this.NFTImageUrl || 'https://liker.land/images/og/writing-nft.jpg'; + this.nftImageURL || 'https://liker.land/images/og/writing-nft.jpg'; return { title, meta: [ @@ -276,7 +276,6 @@ export default { }, data() { return { - nftMetadata: {}, // For