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

✨ [NFT Details] Override NFT Class metadata with NFT metadata #807

Merged
merged 4 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 26 additions & 8 deletions src/mixins/nft.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -32,6 +30,7 @@ import {
getISCNRecord,
getNFTClassCollectionType,
formatNFTEventsToHistory,
parseNFTMetadataURL,
} from '~/util/nft';
import { formatNumberWithUnit, formatNumberWithLIKE } from '~/util/ui';

Expand Down Expand Up @@ -99,6 +98,7 @@ export default {
'getNFTClassOwnerInfoById',
'getNFTClassOwnerCount',
'getNFTClassCollectedCount',
'getNFTMetadataByNFTClassAndNFTId',
'LIKEPriceInUSD',
'uiIsOpenCollectModal',
'uiTxTargetClassId',
Expand All @@ -107,6 +107,11 @@ export default {
NFTClassMetadata() {
return this.getNFTClassMetadataById(this.classId) || {};
},
nftMetadata() {
return (
this.getNFTMetadataByNFTClassAndNFTId(this.classId, this.nftId) || {}
);
},
nftClassCollectionType() {
return getNFTClassCollectionType(this.NFTClassMetadata);
},
Expand Down Expand Up @@ -134,22 +139,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;
},
Expand Down Expand Up @@ -321,7 +339,7 @@ export default {
...mapActions([
'lazyGetUserInfoByAddress',
'fetchNFTPurchaseInfo',
'fetchNFTMetadata',
'fetchNFTClassMetadata',
'fetchNFTOwners',
'initIfNecessary',
'uiToggleCollectModal',
Expand All @@ -344,7 +362,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
Expand Down
4 changes: 2 additions & 2 deletions src/mixins/portfolio.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ export default {
methods: {
...mapActions([
'fetchNFTListByAddress',
'fetchNFTMetadata',
'fetchNFTClassMetadata',
'fetchNFTPurchaseInfo',
'fetchNFTOwners',
]),
Expand Down Expand Up @@ -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
Expand Down
32 changes: 16 additions & 16 deletions src/pages/nft/class/_classId/_nftId.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,17 @@
:is-writing-nft="nftIsWritingNFT"
>
<NFTPagePreviewCard
:url="NFTExternalUrl"
:image-bg-color="NFTImageBackgroundColor"
:image-url="NFTImageUrl"
:url="nftExternalURL"
:image-bg-color="nftImageBackgroundColor"
:image-url="nftImageURL"
:avatar-url="creatorAvatar"
:avatar-size="40"
:is-avatar-outlined="isCreatorCivicLiker"
:iscn-owner="iscnOwner"
:iscn-url="iscnURL"
:display-name="creatorDisplayName"
:nft-name="NFTName"
:nft-description="NFTDescription"
:nft-name="nftName"
:nft-description="nftDescription"
:nft-price="NFTPrice"
:class-collection-type="nftClassCollectionType"
:class-collection-name="nftClassCollectionName"
Expand Down Expand Up @@ -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: [
Expand Down Expand Up @@ -318,24 +318,22 @@ 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({
name: 'nft-class-classId-share',
params: { classId },
query: { referrer },
});
return;
return undefined;
}
try {
await Promise.all([
store.dispatch('fetchNFTMetadata', classId),
store.dispatch('fetchNFTClassMetadata', classId),
store.dispatch('fetchNFTMetadata', { classId, nftId }),
store.dispatch('lazyGetNFTPurchaseInfo', classId).catch(err => {
if (err.response?.data !== 'NFT_CLASS_NOT_FOUND') {
// eslint-disable-next-line no-console
Expand All @@ -357,7 +355,9 @@ export default {
message: 'NFT_FETCH_ERROR',
});
}
return undefined;
}
return { action };
},
async mounted() {
try {
Expand Down Expand Up @@ -390,7 +390,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);
Expand Down
2 changes: 1 addition & 1 deletion src/pages/nft/class/_classId/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 47 additions & 8 deletions src/store/modules/nft.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import * as TYPES from '../mutation-types';
const state = () => ({
purchaseInfoByClassIdMap: {},
metadataByClassIdMap: {},
metadataByNFTClassAndNFTIdMap: {},
ownerInfoByClassIdMap: {},
userClassIdListMap: {},
userLastCollectedTimestampMap: {},
Expand All @@ -28,6 +29,13 @@ const mutations = {
[TYPES.NFT_SET_NFT_CLASS_METADATA](state, { classId, metadata }) {
Vue.set(state.metadataByClassIdMap, classId, metadata);
},
[TYPES.NFT_SET_NFT_METADATA](state, { classId, nftId, metadata }) {
Vue.set(
state.metadataByNFTClassAndNFTIdMap,
`${classId}-${nftId}`,
metadata
);
},
[TYPES.NFT_SET_NFT_CLASS_OWNER_INFO](state, { classId, info }) {
Vue.set(state.ownerInfoByClassIdMap, classId, info);
},
Expand Down Expand Up @@ -84,6 +92,8 @@ const getters = {
(acc, val) => acc + val.length,
0
),
getNFTMetadataByNFTClassAndNFTId: state => (classId, nftId) =>
state.metadataByNFTClassAndNFTIdMap[`${classId}-${nftId}`],
getUserLastCollectedTimestampByAddress: state => address =>
state.userLastCollectedTimestampMap[address],
getNFTClassIdListSorterForCreated: (_, getters) => ({
Expand Down Expand Up @@ -162,13 +172,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,
Expand All @@ -185,18 +195,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)
Expand All @@ -219,6 +235,29 @@ const actions = {
commit(TYPES.NFT_SET_NFT_CLASS_METADATA, { classId, metadata });
return metadata;
},
async fetchNFTMetadata({ commit }, { classId, nftId }) {
let metadata;
const { nft: chainMetadata } = await this.$api.$get(
api.getChainNFTMetadataEndpoint(classId, nftId)
);
const { uri, data: { metadata: nftMetadata = {} } = {} } =
chainMetadata || {};
metadata = {
uri,
...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 };
}
commit(TYPES.NFT_SET_NFT_METADATA, { classId, nftId, metadata });
return metadata;
},
async fetchNFTOwners({ commit }, classId) {
const { owners } = await this.$api.$get(api.getNFTOwners(classId));
const info = formatOwnerInfoFromChain(owners);
Expand Down
1 change: 1 addition & 0 deletions src/store/mutation-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const NFT_SET_NFT_CLASS_PURCHASE_INFO =
'NFT_SET_NFT_CLASS_PURCHASE_INFO';
export const NFT_SET_NFT_CLASS_METADATA = 'NFT_SET_NFT_CLASS_METADATA';
export const NFT_SET_NFT_CLASS_OWNER_INFO = 'NFT_SET_NFT_CLASS_OWNER_INFO';
export const NFT_SET_NFT_METADATA = 'NFT_SET_NFT_METADATA';
export const NFT_SET_USER_CLASSID_LIST_MAP = 'NFT_SET_USER_CLASSID_LIST_MAP';
export const NFT_SET_USER_LAST_COLLECTED_TIMESTAMP_MAP =
'NFT_SET_USER_LAST_COLLECTED_TIMESTAMP_MAP';
Expand Down
5 changes: 4 additions & 1 deletion src/util/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 9 additions & 0 deletions src/util/nft.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx';
import * as api from '@/util/api';
import { deriveAllPrefixedAddresses } from './cosmos';
import {
ARWEAVE_ENDPOINT,
IPFS_VIEW_GATEWAY_URL,
LIKECOIN_CHAIN_NFT_RPC,
LIKECOIN_CHAIN_MIN_DENOM,
LIKECOIN_NFT_API_WALLET,
Expand Down Expand Up @@ -289,3 +291,10 @@ export function formatOwnerInfoFromChain(owners) {
});
return ownerInfo;
}

export function parseNFTMetadataURL(url) {
const [schema, path] = url.split('://');
if (schema === 'ar') return `${ARWEAVE_ENDPOINT}/${path}`;
if (schema === 'ipfs') return `${IPFS_VIEW_GATEWAY_URL}/${path}`;
return url;
}