From c41d170b05154f1434c4aad53527b471dd641650 Mon Sep 17 00:00:00 2001 From: William Chong <6198816+williamchong@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:15:41 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=90=9B=20Fix=20collection=20includesO?= =?UTF-8?q?bject=20json-ld=20(#1885)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ๐Ÿ› Fix collection includesObject json-ld * ๐Ÿ› Fix missing context in json-ld * ๐Ÿ“ˆ Update productId in json and event * ๐Ÿ“ˆ Add book description to edition description --- src/nuxt.config.js | 40 ++---------- src/pages/about/writing-nft.vue | 3 + src/pages/civic/index.vue | 2 + src/pages/index.vue | 2 + src/pages/nft/class/_classId/_nftId.vue | 3 + src/pages/nft/class/_classId/index.vue | 14 ++++- .../nft/collection/_collectionId/index.vue | 63 +++++++++++-------- src/util/EventLogger.js | 29 ++++++--- 8 files changed, 86 insertions(+), 70 deletions(-) diff --git a/src/nuxt.config.js b/src/nuxt.config.js index 4720f49fa..6dc752702 100644 --- a/src/nuxt.config.js +++ b/src/nuxt.config.js @@ -164,16 +164,19 @@ const nuxtConfig = { ], brand: [ { + '@context': 'http://www.schema.org', '@type': 'Brand', url: 'https://liker.land/about/writing-nft', name: 'Writing NFT', }, { + '@context': 'http://www.schema.org', '@type': 'Brand', url: 'https://liker.land/about/nft-book', name: 'NFT Book', }, { + '@context': 'http://www.schema.org', '@type': 'Brand', url: 'https://liker.land/civic', name: 'Civic Liker', @@ -188,42 +191,7 @@ const nuxtConfig = { operatingSystem: 'All', url: 'https://liker.land', offers: { - '@type': 'Offer', - price: '0', - priceCurrency: 'USD', - }, - }, - { - '@context': 'http://www.schema.org', - '@type': 'MobileApplication', - name: 'Liker Land', - applicationCategory: 'LifestyleApplication', - operatingSystem: 'IOS', - url: 'https://apps.apple.com/app/liker-land/id1248232355', - aggregateRating: { - '@type': 'AggregateRating', - ratingValue: '4.3', - ratingCount: '16', - }, - offers: { - '@type': 'Offer', - price: '0', - priceCurrency: 'USD', - }, - }, - { - '@context': 'http://www.schema.org', - '@type': 'MobileApplication', - name: 'Liker Land', - applicationCategory: 'LifestyleApplication', - operatingSystem: 'ANDROID', - url: 'https://play.google.com/store/apps/details?id=com.oice', - aggregateRating: { - '@type': 'AggregateRating', - ratingValue: '3.8', - ratingCount: '1699', - }, - offers: { + '@context': 'http://www.schema.org', '@type': 'Offer', price: '0', priceCurrency: 'USD', diff --git a/src/pages/about/writing-nft.vue b/src/pages/about/writing-nft.vue index 8906145dc..d60e7082a 100644 --- a/src/pages/about/writing-nft.vue +++ b/src/pages/about/writing-nft.vue @@ -50,15 +50,18 @@ export default { '@context': 'http://www.schema.org', '@type': 'FAQPage', about: { + '@context': 'http://www.schema.org', '@type': 'Brand', url: `${EXTERNAL_HOST}/about/writing-nft`, name: 'Writing NFT', }, mainEntity: this.$t('faq_list').map( ({ q: question, a: answer }) => ({ + '@context': 'http://www.schema.org', '@type': 'Question', name: question, acceptedAnswer: { + '@context': 'http://www.schema.org', '@type': 'Answer', text: answer, }, diff --git a/src/pages/civic/index.vue b/src/pages/civic/index.vue index 6d27f47f0..f8d245ebb 100644 --- a/src/pages/civic/index.vue +++ b/src/pages/civic/index.vue @@ -71,12 +71,14 @@ export default { image: [ogImage], description, brand: { + '@context': 'http://www.schema.org', '@type': 'Brand', url: `${EXTERNAL_HOST}/civic`, name: 'Civic Liker', }, url: `${EXTERNAL_HOST}${this.$route.path}`, offers: { + '@context': 'http://www.schema.org', '@type': 'Offer', price: '0', priceCurrency: 'USD', diff --git a/src/pages/index.vue b/src/pages/index.vue index ae69138a1..5e27c93fd 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -847,9 +847,11 @@ export default { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: this.faqs.map(({ question, answer }) => ({ + '@context': 'http://www.schema.org', '@type': 'Question', name: question, acceptedAnswer: { + '@context': 'http://www.schema.org', '@type': 'Answer', text: answer, }, diff --git a/src/pages/nft/class/_classId/_nftId.vue b/src/pages/nft/class/_classId/_nftId.vue index 502e018c6..1354401b3 100644 --- a/src/pages/nft/class/_classId/_nftId.vue +++ b/src/pages/nft/class/_classId/_nftId.vue @@ -463,6 +463,7 @@ export default { name: title, encoding: [ { + '@context': 'http://www.schema.org', '@type': 'MediaObject', contentUrl: this.nftModelURL, encodingFormat: 'model/gltf-json', @@ -473,12 +474,14 @@ export default { let brand; if (this.isWritingNft) { brand = { + '@context': 'http://www.schema.org', '@type': 'Brand', url: `${EXTERNAL_HOST}/about/writing-nft`, name: 'Writing NFT', }; } else if (this.nftIsNFTBook) { brand = { + '@context': 'http://www.schema.org', '@type': 'Brand', url: `${EXTERNAL_HOST}/about/nft-book`, name: 'NFT Book', diff --git a/src/pages/nft/class/_classId/index.vue b/src/pages/nft/class/_classId/index.vue index 6b58e4369..a187ef38e 100644 --- a/src/pages/nft/class/_classId/index.vue +++ b/src/pages/nft/class/_classId/index.vue @@ -548,6 +548,7 @@ export default { name: title, encoding: [ { + '@context': 'http://www.schema.org', '@type': 'MediaObject', contentUrl: this.nftModelURL, encodingFormat: 'model/gltf-json', @@ -566,6 +567,7 @@ export default { image: [ogImage], description, brand: { + '@context': 'http://www.schema.org', '@type': 'Brand', url: `${EXTERNAL_HOST}/about/writing-nft`, name: 'Writing NFT', @@ -576,6 +578,7 @@ export default { datePublished: this.iscnData?.recordTimestamp, url: `${EXTERNAL_HOST}${this.$route.path}`, offers: { + '@context': 'http://www.schema.org', '@type': 'Offer', seller: iscnOwnerPerson, price: NFTPriceUSD, @@ -598,6 +601,7 @@ export default { image: [ogImage], description, brand: { + '@context': 'http://www.schema.org', '@type': 'Brand', url: 'https://liker.land/about/nft-book', name: 'NFT Book', @@ -606,6 +610,7 @@ export default { sku: this.classId, iscn: this.iscnId, isbn: this.iscnData?.contentMetadata?.isbn, + inLanguage: this.iscnData?.contentMetadata?.inLanguage, productGroupID: this.classId, datePublished: this.iscnData?.recordTimestamp, bookFormat: 'https://schema.org/EBook', @@ -615,28 +620,35 @@ export default { }; this.nftEditions.forEach(e => { schemas.push({ + '@context': 'http://www.schema.org', '@type': ['Book', 'Product'], '@id': `@${this.classId}-${e.index}`, + url: `${EXTERNAL_HOST}${this.$route.path}?price_index=${e.index}`, + productID: `${this.classId}-${e.index}`, name: `${title} - ${e.name}`, image: [ogImage], sku: `${this.classId}-${e.index}`, inProductGroupWithID: this.classId, iscn: this.iscnId, isbn: this.iscnData?.contentMetadata?.isbn, + inLanguage: this.iscnData?.contentMetadata?.inLanguage, bookFormat: 'https://schema.org/EBook', bookEdition: e.name, - description: e.description, + description: `${e.description}\n${description}`, brand: { + '@context': 'http://www.schema.org', '@type': 'Brand', url: 'https://liker.land/about/nft-book', name: 'NFT Book', }, offers: { + '@context': 'http://www.schema.org', '@type': 'Offer', seller: iscnOwnerPerson, price: e.price, priceCurrency: 'USD', availability: e.stock ? 'LimitedAvailability' : 'OutOfStock', + itemCondition: 'https://schema.org/NewCondition', checkoutPageURLTemplate: getNFTBookPurchaseLink({ classId: this.classId, priceIndex: e.index, diff --git a/src/pages/nft/collection/_collectionId/index.vue b/src/pages/nft/collection/_collectionId/index.vue index 12930a0c6..a9951805a 100644 --- a/src/pages/nft/collection/_collectionId/index.vue +++ b/src/pages/nft/collection/_collectionId/index.vue @@ -163,7 +163,9 @@ export default { if (this.collectionPrice) { schemas.push({ '@context': 'http://schema.org', - '@type': 'ProductCollection', + '@type': ['Product', 'ProductCollection'], + url: `${EXTERNAL_HOST}/nft/collection/${this.collectionId}`, + productID: this.collectionId, name: this.collectionName, description: this.collectionDescription, image: ogImage, @@ -175,33 +177,43 @@ export default { iscn_owner: iscnOwner, } = this.getNFTClassMetadataById(id); return { - '@type': this.collectionIsBook ? 'Book' : 'CreativeWork', - name: className, - description: classDescription, - image: classImage, - url: `${EXTERNAL_HOST}/nft/class/${id}`, - author: iscnOwner - ? { - '@context': 'http://www.schema.org', - '@type': 'Person', - url: `${EXTERNAL_HOST}/${iscnOwner}`, - identifier: iscnOwner, - } - : undefined, - brand: this.collectionIsBook - ? { - '@type': 'Brand', - url: `${EXTERNAL_HOST}/about/nft-book`, - name: 'NFT Book', - } - : { - '@type': 'Brand', - url: `${EXTERNAL_HOST}/about/writing-nft`, - name: 'Writing NFT', - }, + '@context': 'http://www.schema.org', + '@type': 'TypeAndQuantityNode', + typeOfGood: { + '@context': 'http://www.schema.org', + '@type': this.collectionIsBook ? 'Book' : 'CreativeWork', + name: className, + description: classDescription, + image: classImage, + url: `${EXTERNAL_HOST}/nft/class/${id}`, + author: iscnOwner + ? { + '@context': 'http://www.schema.org', + '@type': 'Person', + url: `${EXTERNAL_HOST}/${iscnOwner}`, + identifier: iscnOwner, + } + : undefined, + brand: this.collectionIsBook + ? { + '@context': 'http://www.schema.org', + '@type': 'Brand', + url: `${EXTERNAL_HOST}/about/nft-book`, + name: 'NFT Book', + } + : { + '@context': 'http://www.schema.org', + '@type': 'Brand', + url: `${EXTERNAL_HOST}/about/writing-nft`, + name: 'Writing NFT', + }, + }, + amountOfThisGood: '1', + unitCode: 'C62', }; }), offers: { + '@context': 'http://www.schema.org', '@type': 'Offer', price: this.collectionPrice, priceCurrency: 'USD', @@ -214,6 +226,7 @@ export default { availability: this.collection?.stock ? 'LimitedAvailability' : 'OutOfStock', + itemCondition: 'https://schema.org/NewCondition', checkoutPageURLTemplate: getNFTBookPurchaseLink({ collectionId: this.collectionId, }), diff --git a/src/util/EventLogger.js b/src/util/EventLogger.js index cb90e7adb..7f151dd09 100644 --- a/src/util/EventLogger.js +++ b/src/util/EventLogger.js @@ -174,7 +174,10 @@ export function logPurchaseFlowEvent( value: price, currency, items: items.map(i => { - const itemId = i.productId || i.collectionId || i.classId; + let itemId = i.productId || i.collectionId || i.classId; + if (i.priceIndex !== undefined) { + itemId = `${itemId}-${i.priceIndex}`; + } return { item_id: itemId, item_name: i.name?.substring(0, 100) || itemId, @@ -212,13 +215,23 @@ export function logPurchaseFlowEvent( value: price, order_id: paymentId || txHash, content_type: 'product', - contents: items.map(i => ({ - id: i.productId || i.collectionId || i.classId, - quantity: i.quantity || 1, - })), - content_ids: items.map( - i => i.productId || i.collectionId || i.classId - ), + contents: items.map(i => { + let id = i.productId || i.collectionId || i.classId; + if (i.priceIndex !== undefined) { + id = `${id}-${i.priceIndex}`; + } + return { + id, + quantity: i.quantity || 1, + }; + }), + content_ids: items.map(i => { + let id = i.productId || i.collectionId || i.classId; + if (i.priceIndex !== undefined) { + id = `${id}-${i.priceIndex}`; + } + return id; + }), }, eventID ? { eventID } : undefined ); From b4d0c2e00466e55e904ce569250d78e283baa107 Mon Sep 17 00:00:00 2001 From: AuroraHuang22 Date: Fri, 11 Oct 2024 13:11:48 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=94=A7=20Update=20sign=20image=20bann?= =?UTF-8?q?er=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constant/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/constant/index.js b/src/constant/index.js index 9f7a6da0e..5237fbfb2 100644 --- a/src/constant/index.js +++ b/src/constant/index.js @@ -350,6 +350,10 @@ export const NFT_BOOK_WITH_SIGN_IMAGE_SET = new Map( 'likenft1nekez4y50uk0dmgxuxql7v2vnhy3wqa24ld46hk4frlwcvwpr88selunrr', ['้™ณๅฅๆฐ‘'], ], + [ + 'likenft1gp28fe9uzqdadrps67hz20035m0hh9zu9m8kzvz6gdawvms5xtts5m6qds', + ['่ณดไฝฉ้œž'], + ], ] : [ ['likenft154xhw0qyds5pgvsyc7379lnkyvwqkvv2zvmmh2gn5qrewljeqwys2sju6x'], From acc6cdb08ec07d288d48cc907c5d119cbc218509 Mon Sep 17 00:00:00 2001 From: William Chong Date: Fri, 11 Oct 2024 17:52:55 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=93=88=20Add=20priceIndex=20in=20purc?= =?UTF-8?q?hase=20flow=20events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/NFTBook/CrossSellDialog.vue | 4 +++- src/mixins/nft.js | 2 ++ src/pages/nft/claim/index.vue | 13 +++++++++++-- src/pages/nft/class/_classId/_nftId.vue | 1 + src/pages/nft/class/_classId/index.vue | 14 ++++++++++++++ src/pages/nft/fiat/stripe.vue | 1 + src/pages/nft/gift/index.vue | 4 +++- 7 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/components/NFTBook/CrossSellDialog.vue b/src/components/NFTBook/CrossSellDialog.vue index 139bc2d53..df24a033a 100644 --- a/src/components/NFTBook/CrossSellDialog.vue +++ b/src/components/NFTBook/CrossSellDialog.vue @@ -236,7 +236,8 @@ export default { }); } else { // NOTE: Only support single edition for now - const edition = this.getEditionByIndex(0); + const priceIndex = 0; + const edition = this.getEditionByIndex(priceIndex); const hasStock = edition?.stock; if (!hasStock || !this.nftIsCollectable || edition.price === 0) { this.handleReject(); @@ -250,6 +251,7 @@ export default { name: this.NFTName, price: edition.price, classId: this.classId, + priceIndex, quantity: 1, }, ], diff --git a/src/mixins/nft.js b/src/mixins/nft.js index 1676b52ef..141f4cfc3 100644 --- a/src/mixins/nft.js +++ b/src/mixins/nft.js @@ -997,6 +997,7 @@ export default { items: [ { classId: this.classId, + priceIndex: this.editionPriceIndex, price: this.NFTPriceUSD, name: this.NFTName, }, @@ -1131,6 +1132,7 @@ export default { { name: this.NFTName, price: this.NFTPriceUSD, + priceIndex: this.editionPriceIndex, classId, }, ], diff --git a/src/pages/nft/claim/index.vue b/src/pages/nft/claim/index.vue index 733acc1cd..e4e749dbc 100644 --- a/src/pages/nft/claim/index.vue +++ b/src/pages/nft/claim/index.vue @@ -798,6 +798,7 @@ export default { return; } let price; + let priceIndex; if (this.cartId) { const { data } = await this.$api.get( getNFTBookCartStatusEndpoint({ @@ -805,7 +806,7 @@ export default { token: this.token, }) ); - ({ price } = data); + ({ price, priceIndex } = data); const { classIdsWithPrice = [], collectionIdsWithPrice = [], @@ -908,7 +909,13 @@ export default { if (!free && !this.giftInfo && redirect && query.type === 'nft_book') { const items = this.cartItems.length ? this.cartItems.map(item => { - const { classId, collectionId, price, quantity = 1 } = item; + const { + classId, + collectionId, + price, + priceIndex, + quantity = 1, + } = item; const name = classId ? this.getNFTClassMetadataById(classId)?.name : this.getNFTCollectionInfoByCollectionId(collectionId)?.name[ @@ -918,6 +925,7 @@ export default { name, classId, collectionId, + priceIndex, price, quantity, }; @@ -927,6 +935,7 @@ export default { name: this.productName, classId: this.classId, collectionId: this.collectionId, + priceIndex, price, quantity: this.quantity, }, diff --git a/src/pages/nft/class/_classId/_nftId.vue b/src/pages/nft/class/_classId/_nftId.vue index 1354401b3..7a2d60dcc 100644 --- a/src/pages/nft/class/_classId/_nftId.vue +++ b/src/pages/nft/class/_classId/_nftId.vue @@ -640,6 +640,7 @@ export default { { name: this.NFTName, price: this.NFTPriceUSD, + priceIndex: this.editionPriceIndex, classId: this.classId, }, ], diff --git a/src/pages/nft/class/_classId/index.vue b/src/pages/nft/class/_classId/index.vue index a187ef38e..d186b84e9 100644 --- a/src/pages/nft/class/_classId/index.vue +++ b/src/pages/nft/class/_classId/index.vue @@ -891,6 +891,7 @@ export default { { name: this.NFTName, classId: this.classId, + priceIndex: this.editionPriceIndex, price: this.NFTPriceUSD, }, ], @@ -940,6 +941,7 @@ export default { name: this.NFTName, price: customPriceInDecimal || edition.price, classId: this.classId, + priceIndex: edition.index, quantity: this.quantity, }, ], @@ -1357,6 +1359,18 @@ export default { this.classId, 1 ); + logPurchaseFlowEvent(this, 'view_item', { + items: [ + { + name: this.NFTName, + classId: this.classId, + priceIndex: this.editionPriceIndex, + price: this.NFTPriceUSD, + }, + ], + price: this.NFTPriceUSD, + currency: 'USD', + }); }, handleInputCustomPrice(price) { this.customPrice = Number(price); diff --git a/src/pages/nft/fiat/stripe.vue b/src/pages/nft/fiat/stripe.vue index f1f865e5f..4f3e62e06 100644 --- a/src/pages/nft/fiat/stripe.vue +++ b/src/pages/nft/fiat/stripe.vue @@ -130,6 +130,7 @@ export default { name: this.NFTName, price: this.result.fiatPrice, classId: this.classId, + priceIndex: this.editionPriceIndex, }, ], price: this.result.fiatPrice, diff --git a/src/pages/nft/gift/index.vue b/src/pages/nft/gift/index.vue index a5fdba165..61de86337 100644 --- a/src/pages/nft/gift/index.vue +++ b/src/pages/nft/gift/index.vue @@ -117,6 +117,7 @@ export default { return; } let price; + let priceIndex; if (this.cartId) { const { data } = await this.$api.get( @@ -147,7 +148,7 @@ export default { paymentId: this.paymentId, }) ); - ({ price } = data); + ({ price, priceIndex } = data); } try { if (this.cartItems.length) { @@ -212,6 +213,7 @@ export default { name: this.productName, classId: this.classId, collectionId: this.collectionId, + priceIndex, price, quantity: this.quantity, },