From e574270758ecccc55d7ce8e6d917e99d0971e91f Mon Sep 17 00:00:00 2001 From: fede erbes Date: Wed, 29 Nov 2023 18:12:09 +0100 Subject: [PATCH] fix: logic and ui in RareSatsTabGridItem component (#692) --- package-lock.json | 14 +- package.json | 2 +- .../exoticSatsRow/exoticSatsRow.tsx | 21 +- .../ordinals/tempAddressRareSatsMock.ts | 269 +++++++++++++++++- .../queries/ordinals/useAddressRareSats.ts | 9 +- .../screens/nftDashboard/collectiblesTabs.tsx | 2 +- .../nftDashboard/rareSatsTabGridItem.tsx | 91 ++++-- .../nftDashboard/supportedRarities/index.tsx | 4 +- src/app/utils/rareSats.ts | 6 +- 9 files changed, 365 insertions(+), 53 deletions(-) diff --git a/package-lock.json b/package-lock.json index f2b34ceea..2dd688aec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "@ledgerhq/hw-transport-webusb": "^6.27.13", "@phosphor-icons/react": "^2.0.10", "@react-spring/web": "^9.6.1", - "@secretkeylabs/xverse-core": "3.1.1-e148aa5", + "@secretkeylabs/xverse-core": "4.0.0", "@stacks/connect": "^6.10.2", "@stacks/encryption": "4.3.5", "@stacks/stacks-blockchain-api-types": "6.1.1", @@ -1727,9 +1727,9 @@ } }, "node_modules/@secretkeylabs/xverse-core": { - "version": "3.1.1-e148aa5", - "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/3.1.1-e148aa5/052344a16abd8ca22ae92643c209ac586c004241", - "integrity": "sha512-J52vNGjglWUQ8PHV5t/bPBFDs5bSXBzaPFHVe6KlFs90BFsAFsD9gdGMB0M9wGJgPFNQc820XZne11YJGbmllw==", + "version": "4.0.0", + "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/4.0.0/b2776f6bd4a6eb065b31eafd6ab198c486af7b8d", + "integrity": "sha512-u4XBHz8VYeQGFtpjxfOIMMcx6OAusQx02j/fAanwURHAbgeX8P90esY4s8rtAFcOV16dGRqA/HHEIusnt3d6+Q==", "license": "ISC", "dependencies": { "@bitcoinerlab/secp256k1": "^1.0.2", @@ -16046,9 +16046,9 @@ } }, "@secretkeylabs/xverse-core": { - "version": "3.1.1-e148aa5", - "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/3.1.1-e148aa5/052344a16abd8ca22ae92643c209ac586c004241", - "integrity": "sha512-J52vNGjglWUQ8PHV5t/bPBFDs5bSXBzaPFHVe6KlFs90BFsAFsD9gdGMB0M9wGJgPFNQc820XZne11YJGbmllw==", + "version": "4.0.0", + "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/4.0.0/b2776f6bd4a6eb065b31eafd6ab198c486af7b8d", + "integrity": "sha512-u4XBHz8VYeQGFtpjxfOIMMcx6OAusQx02j/fAanwURHAbgeX8P90esY4s8rtAFcOV16dGRqA/HHEIusnt3d6+Q==", "requires": { "@bitcoinerlab/secp256k1": "^1.0.2", "@noble/secp256k1": "^1.7.1", diff --git a/package.json b/package.json index a917366f4..797339ffe 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "@ledgerhq/hw-transport-webusb": "^6.27.13", "@phosphor-icons/react": "^2.0.10", "@react-spring/web": "^9.6.1", - "@secretkeylabs/xverse-core": "3.1.1-e148aa5", + "@secretkeylabs/xverse-core": "4.0.0", "@stacks/connect": "^6.10.2", "@stacks/encryption": "4.3.5", "@stacks/stacks-blockchain-api-types": "6.1.1", diff --git a/src/app/components/exoticSatsRow/exoticSatsRow.tsx b/src/app/components/exoticSatsRow/exoticSatsRow.tsx index 838f98f7c..9af5e101e 100644 --- a/src/app/components/exoticSatsRow/exoticSatsRow.tsx +++ b/src/app/components/exoticSatsRow/exoticSatsRow.tsx @@ -66,10 +66,12 @@ function ExoticSatsRow({ satAmount, inscriptions, icons, + showNumberOfInscriptions = false, }: { title: string; satAmount: number; inscriptions: SatRangeInscription[]; + showNumberOfInscriptions?: boolean; icons: ReactNode; }) { const { t } = useTranslation('translation', { keyPrefix: 'COMMON' }); @@ -90,14 +92,25 @@ function ExoticSatsRow({ )} /> - {inscriptions.map((inscription) => ( - + {showNumberOfInscriptions && inscriptions.length ? ( + ordinal - {inscription.inscription_number} + {inscriptions.length > 1 + ? `+${inscriptions.length}` + : inscriptions[0].inscription_number} - ))} + ) : ( + inscriptions.map((inscription) => ( + + ordinal + + {inscription.inscription_number} + + + )) + )} {icons} diff --git a/src/app/hooks/queries/ordinals/tempAddressRareSatsMock.ts b/src/app/hooks/queries/ordinals/tempAddressRareSatsMock.ts index 237e4a25f..39a3684a6 100644 --- a/src/app/hooks/queries/ordinals/tempAddressRareSatsMock.ts +++ b/src/app/hooks/queries/ordinals/tempAddressRareSatsMock.ts @@ -141,13 +141,13 @@ export const mockTestCase1: AddressBundleResponse = { results: [], }; -// TestCase 2 - 3 bundles +// TestCase 3 - 6 bundles const { xVersion, ...bundle } = inscriptionPartOfBundle; export const mockTestCase3: AddressBundleResponse = { xVersion: 1, limit: 30, offset: 0, - total: 5, + total: 6, results: [ { block_height: 803128, @@ -181,6 +181,16 @@ export const mockTestCase3: AddressBundleResponse = { id: '09c094c3f1ab71c9be7a356a0f1af21b0e552c18d50372fd3799430c890ef135i0', inscription_number: 123141212, }, + { + content_type: 'text/plain;charset=utf-8', + id: '09c094c3f1ab71c9be7a356a0f1af21b0e552c18d50372fd3799430c890ef135i0', + inscription_number: 123141213, + }, + { + content_type: 'text/plain;charset=utf-8', + id: '09c094c3f1ab71c9be7a356a0f1af21b0e552c18d50372fd3799430c890ef135i0', + inscription_number: 123141214, + }, ], }, { @@ -221,7 +231,7 @@ export const mockTestCase3: AddressBundleResponse = { start: '34234320000000', end: '34234320010000', }, - satributes: ['MYTHIC', 'BLOCK78'], + satributes: ['MYTHIC'], inscriptions: [], }, { @@ -232,7 +242,7 @@ export const mockTestCase3: AddressBundleResponse = { start: '34234320010001', end: '34234320010002', }, - satributes: ['PIZZA'], + satributes: ['PIZZA', 'BLOCK78', 'BLOCK9', 'NAKAMOTO', 'VINTAGE', 'FIRST_TRANSACTION'], inscriptions: [ { content_type: 'text/plain;charset=utf-8', @@ -327,6 +337,17 @@ export const mockTestCase3: AddressBundleResponse = { value: 100, vout: 0, sat_ranges: [ + { + year_mined: 2009, + block: 9, + offset: 0, + range: { + start: '34234320000000', + end: '34234320000003', + }, + satributes: ['UNCOMMON', 'PIZZA', 'PALINDROME', 'BLOCK9_450', 'VINTAGE', 'SILK_ROAD'], + inscriptions: [], + }, { year_mined: 2009, block: 9, @@ -340,6 +361,91 @@ export const mockTestCase3: AddressBundleResponse = { }, ], }, + { + block_height: 803128, + txid: 'f5aa0649f2e5d0c6402c2d6b64ba6ea89e8be836a2ad01cbb0cdcc8721e314d1', + value: 100, + vout: 0, + sat_ranges: [ + { + year_mined: 2009, + block: 9, + offset: 0, + range: { + start: '34234320000000', + end: '34234320000003', + }, + satributes: ['UNCOMMON'], + inscriptions: [], + }, + { + year_mined: 2009, + block: 9, + offset: 0, + range: { + start: '34234320000000', + end: '34234320000003', + }, + satributes: ['NAKAMOTO'], + inscriptions: [], + }, + { + year_mined: 2009, + block: 9, + offset: 0, + range: { + start: '34234320000000', + end: '34234320000003', + }, + satributes: ['SILK_ROAD'], + inscriptions: [], + }, + { + year_mined: 2009, + block: 9, + offset: 0, + range: { + start: '34234320000000', + end: '34234320000003', + }, + satributes: ['SEQUENCE_PALINDROME'], + inscriptions: [], + }, + { + year_mined: 2009, + block: 9, + offset: 0, + range: { + start: '34234320000000', + end: '34234320000003', + }, + satributes: ['PERFECT_PALINCEPTION'], + inscriptions: [], + }, + { + year_mined: 2009, + block: 9, + offset: 0, + range: { + start: '34234320000000', + end: '34234320000003', + }, + satributes: ['VINTAGE'], + inscriptions: [], + }, + { + year_mined: 2009, + block: 9, + offset: 0, + range: { + start: '34234320000000', + end: '34234320000003', + }, + satributes: ['MYTHIC'], + inscriptions: [], + }, + ], + }, bundle, { block_height: 803128, @@ -350,3 +456,158 @@ export const mockTestCase3: AddressBundleResponse = { }, ], }; + +// TestCase 4 - 4 bundles with unsupported types +export const mockTestCase4: AddressBundleResponse = { + xVersion: 1, + limit: 30, + offset: 0, + total: 5, + results: [ + { + block_height: 803128, + txid: 'b8f8aee03af313ef1fbba7316aadf7390c91dc5dd34928a15f708ea4ed642852', + value: 10, + vout: 0, + sat_ranges: [ + { + year_mined: 2009, + block: 11, + offset: 1, + range: { + start: '34234320000003', + end: '34234320000004', + }, + satributes: ['1D_PALINDROME', '2D_PALINDROME', 'BLOCK9_450'], + inscriptions: [], + }, + { + year_mined: 2009, + block: 11, + offset: 2, + range: { + start: '34234320000003', + end: '34234320000004', + }, + satributes: ['PIZZA', 'BLOCK9_450'], + inscriptions: [ + { + content_type: 'image/png', + id: '6b186d467d817e4d086a9d1bf93785d736df6431c1cc9c305571161d616d05d0i0', + inscription_number: 11067475, + }, + ], + }, + { + year_mined: 2009, + block: 10, + offset: 0, + range: { + start: '34234320000000', + end: '34234320000001', + }, + satributes: ['BLOCK9_450'], + inscriptions: [ + { + content_type: 'image/png', + id: '6b186d467d817e4d086a9d1bf93785d736df6431c1cc9c305571161d616d05d0i0', + inscription_number: 11067474, + }, + ], + }, + { + year_mined: 2009, + block: 11, + offset: 3, + range: { + start: '34234320000004', + end: '34234320000005', + }, + satributes: ['BLOCK9_450'], + inscriptions: [], + }, + ], + }, + { + block_height: 803128, + txid: 'b8f8aee03af313ef1fbba7316aadf7390c91dc5dd34928a15f708ea4ed642852', + value: 10, + vout: 0, + sat_ranges: [ + { + year_mined: 2009, + block: 11, + offset: 0, + range: { + start: '34234320000003', + end: '34234320000004', + }, + satributes: ['EPIC', '1D_PALINDROME', '2D_PALINDROME', 'BLOCK9_450', 'VINTAGE'], + inscriptions: [], + }, + { + year_mined: 2009, + block: 11, + offset: 1, + range: { + start: '34234320000003', + end: '34234320000004', + }, + satributes: ['PIZZA', 'BLOCK9_450'], + inscriptions: [ + { + content_type: 'image/png', + id: '6b186d467d817e4d086a9d1bf93785d736df6431c1cc9c305571161d616d05d0i0', + inscription_number: 11067475, + }, + ], + }, + { + year_mined: 2009, + block: 10, + offset: 2, + range: { + start: '34234320000000', + end: '34234320000001', + }, + satributes: ['BLOCK9_450', 'BLOCK78', 'FIBONACCI'], + inscriptions: [ + { + content_type: 'image/png', + id: '6b186d467d817e4d086a9d1bf93785d736df6431c1cc9c305571161d616d05d0i0', + inscription_number: 11067474, + }, + ], + }, + { + year_mined: 2009, + block: 10, + offset: 3, + range: { + start: '34234320000000', + end: '34234320000001', + }, + satributes: ['BLOCK9_450', 'BLOCK78', 'FIBONACCI', 'BLACK_EPIC'], + inscriptions: [ + { + content_type: 'image/png', + id: '6b186d467d817e4d086a9d1bf93785d736df6431c1cc9c305571161d616d05d0i0', + inscription_number: 11067473, + }, + ], + }, + { + year_mined: 2009, + block: 11, + offset: 4, + range: { + start: '34234320000004', + end: '34234320000005', + }, + satributes: ['BLOCK9_450'], + inscriptions: [], + }, + ], + }, + ], +}; diff --git a/src/app/hooks/queries/ordinals/useAddressRareSats.ts b/src/app/hooks/queries/ordinals/useAddressRareSats.ts index 466605de2..6c588956e 100644 --- a/src/app/hooks/queries/ordinals/useAddressRareSats.ts +++ b/src/app/hooks/queries/ordinals/useAddressRareSats.ts @@ -12,6 +12,7 @@ import { mockData, mockTestCase1, mockTestCase3, + mockTestCase4, } from './tempAddressRareSatsMock'; const PAGE_SIZE = 30; @@ -41,12 +42,18 @@ export const useAddressRareSats = () => { throw new Error('Error response from API'); } - // 1 BUNDLE with 4 sat ranges + // 6 bundles with different combinations of sats and inscriptions const testcase3 = localStorage.getItem('testcase3'); if (testcase3) { return mockTestCase3; } + // 2 bundles with different combinations of sats and inscriptions but with unsupported types + const testcase4 = localStorage.getItem('testcase4'); + if (testcase4) { + return mockTestCase4; + } + return mockData; } diff --git a/src/app/screens/nftDashboard/collectiblesTabs.tsx b/src/app/screens/nftDashboard/collectiblesTabs.tsx index f2789daee..c68db4df1 100644 --- a/src/app/screens/nftDashboard/collectiblesTabs.tsx +++ b/src/app/screens/nftDashboard/collectiblesTabs.tsx @@ -16,7 +16,7 @@ import Notice from './notice'; import RareSatsTabGridItem from './rareSatsTabGridItem'; import type { NftDashboardState } from './useNftDashboard'; -const MAX_SATS_ITEMS_EXTENSION = 6; +const MAX_SATS_ITEMS_EXTENSION = 5; const MAX_SATS_ITEMS_GALLERY = 20; export const GridContainer = styled.div<{ diff --git a/src/app/screens/nftDashboard/rareSatsTabGridItem.tsx b/src/app/screens/nftDashboard/rareSatsTabGridItem.tsx index ac9764835..03182618f 100644 --- a/src/app/screens/nftDashboard/rareSatsTabGridItem.tsx +++ b/src/app/screens/nftDashboard/rareSatsTabGridItem.tsx @@ -2,7 +2,7 @@ import ExoticSatsRow from '@components/exoticSatsRow/exoticSatsRow'; import RareSatIcon from '@components/rareSatIcon/rareSatIcon'; import useSatBundleDataReducer from '@hooks/stores/useSatBundleReducer'; import { DotsThree } from '@phosphor-icons/react'; -import { Bundle } from '@secretkeylabs/xverse-core'; +import { Bundle, RareSatsType } from '@secretkeylabs/xverse-core'; import { StyledP } from '@ui-library/common.styled'; import { getFormattedTxIdVoutFromBundle } from '@utils/rareSats'; import { useNavigate } from 'react-router-dom'; @@ -44,40 +44,70 @@ function RareSatsTabGridItem({ bundle, maxItems }: { bundle: Bundle; maxItems: n const renderedIcons = () => { let totalIconsDisplayed = 0; let totalTilesDisplayed = 0; - return bundle.satributes + + const icons: (RareSatsType | 'ellipsis' | '+X')[][] = []; + let overLimitSatsIndex: number | null = null; + let totalSats = 0; + let totalTiles = 0; + bundle.satributes .filter((satributes) => !(satributes.includes('COMMON') && bundle.satributes.length > 1)) - .map((sats, index) => { - if (totalIconsDisplayed > maxItems) { - return null; - } + .forEach((sats, index) => { + totalSats += sats.length; + totalTiles += 1; - if (totalIconsDisplayed >= maxItems - 1) { - totalIconsDisplayed += 1; - return ( - - - +{bundle.satributes.length - totalTilesDisplayed} - - - ); + const isOverLimit = + totalIconsDisplayed + sats.length > maxItems - (sats.length > 1 ? 2 : 1); + // we add ranges till we reach the limit and we store the index of the range that is over the limit + if (isOverLimit || overLimitSatsIndex !== null) { + overLimitSatsIndex = overLimitSatsIndex !== null ? overLimitSatsIndex : index; + return; } totalTilesDisplayed += 1; - return ( - - {sats.map((sattribute, indexSattributes) => { - totalIconsDisplayed += 1; - if (totalIconsDisplayed >= maxItems - 1) { - return null; - } - // eslint-disable-next-line react/no-array-index-key - return ; - })} - {totalIconsDisplayed > maxItems - 2 ? ( - - ) : null} - - ); + totalIconsDisplayed += sats.length; + icons.push(sats); }); + + // if we have more than 1 range and we have reached the limit we add ellipsis and +X + if (overLimitSatsIndex !== null) { + const sats = bundle.satributes[overLimitSatsIndex]; + const satsToDisplay = maxItems - totalIconsDisplayed - 2; + const firstSats = sats.slice(0, satsToDisplay); + // we add ellipsis only if we have more than 1 slot left counting the +X + if (firstSats.length > 0) { + totalTilesDisplayed += 1; + icons.push([...firstSats, 'ellipsis']); + } + + if (totalSats > maxItems) { + icons.push(['+X']); + } + } + + return icons.map((sats, index) => ( + + {sats.map((sattribute, indexSatributes) => { + if (sattribute === 'ellipsis') { + return ( + + ); + } + + if (sattribute === '+X') { + return ( + + +{totalTiles - totalTilesDisplayed} + + ); + } + // eslint-disable-next-line react/no-array-index-key + return ; + })} + + )); }; const bundleId = getFormattedTxIdVoutFromBundle(bundle); @@ -88,6 +118,7 @@ function RareSatsTabGridItem({ bundle, maxItems }: { bundle: Bundle; maxItems: n title={bundleId} satAmount={bundle.value} inscriptions={bundle.inscriptions} + showNumberOfInscriptions icons={renderedIcons()} /> diff --git a/src/app/screens/nftDashboard/supportedRarities/index.tsx b/src/app/screens/nftDashboard/supportedRarities/index.tsx index 9e75db492..ce91f4cda 100644 --- a/src/app/screens/nftDashboard/supportedRarities/index.tsx +++ b/src/app/screens/nftDashboard/supportedRarities/index.tsx @@ -1,6 +1,6 @@ import TopRow from '@components/topRow'; import { ArrowUpRight } from '@phosphor-icons/react'; -import { RoadArmorRareSats, Sattributes } from '@secretkeylabs/xverse-core'; +import { RodarmorRareSats, Satributes } from '@secretkeylabs/xverse-core'; import { StyledP } from '@ui-library/common.styled'; import { BLOG_LINK } from '@utils/constants'; import { useTranslation } from 'react-i18next'; @@ -54,7 +54,7 @@ const MainContainer = styled.div((props) => ({ backgroundColor: Theme.colors.elevation0, })); -const rarityTypes = [...RoadArmorRareSats, ...Sattributes]; +const rarityTypes = [...RodarmorRareSats, ...Satributes]; function SupportedRarities() { const navigate = useNavigate(); diff --git a/src/app/utils/rareSats.ts b/src/app/utils/rareSats.ts index 00bf055f9..1506977ed 100644 --- a/src/app/utils/rareSats.ts +++ b/src/app/utils/rareSats.ts @@ -1,8 +1,8 @@ import { Bundle, RareSatsType, - RoadArmorRareSats, - RoadArmorRareSatsType, + RodarmorRareSats, + RodarmorRareSatsType, } from '@secretkeylabs/xverse-core'; import { t } from 'i18next'; import { getTruncatedAddress } from './helper'; @@ -31,7 +31,7 @@ export const getSatLabel = (satributes: RareSatsType[]): string => { } // we expect to roadarmor sats be in the first position - if (RoadArmorRareSats.includes(satributes[0] as RoadArmorRareSatsType)) { + if (RodarmorRareSats.includes(satributes[0] as RodarmorRareSatsType)) { return `${getRareSatsLabelByType(satributes[0])} ${t( isLengthGrateThanTwo ? 'COMMON.COMBO' : `RARE_SATS.RARITY_LABEL.${satributes[1]}`, )}`;