From 654b3f565d35789e2b94a789461322e70a3b9b55 Mon Sep 17 00:00:00 2001 From: Lautaro Petaccio <1120791+LautaroPetaccio@users.noreply.github.com> Date: Mon, 6 May 2024 17:00:31 -0300 Subject: [PATCH] feat: Add Asset Utility (#2243) * feat: Add Wearable Utility * fix: Rename WearableUtility to AssetUtility * fix: CategoryBadge types --- webapp/package-lock.json | 27 +--- webapp/package.json | 4 +- .../AssetUtility/AssetUtility.module.css | 9 ++ .../AssetUtility/AssetUtility.spec.tsx | 22 +++ .../AssetPage/AssetUtility/AssetUtility.tsx | 20 +++ .../AssetUtility/AssetUtility.types.ts | 3 + .../AssetPage/AssetUtility/index.ts | 2 + .../AssetPage/CategoryBadge/CategoryBadge.tsx | 12 +- .../EmoteDetail/EmoteDetail.module.css | 16 ++ .../AssetPage/EmoteDetail/EmoteDetail.tsx | 16 +- .../AssetPage/IconBadge/IconBadge.css | 142 ------------------ .../AssetPage/IconBadge/IconBadge.tsx | 29 ---- .../AssetPage/IconBadge/IconBadge.types.ts | 10 -- .../components/AssetPage/IconBadge/index.ts | 3 - .../ItemDetail/ItemDetail.module.css | 23 ++- .../AssetPage/ItemDetail/ItemDetail.tsx | 16 +- .../LinkedIconBadge/LinkedIconBadge.tsx | 18 +++ .../LinkedIconBadge/LinkedIconBadge.types.ts | 2 + .../AssetPage/LinkedIconBadge/index.ts | 4 + .../AssetPage/SmartBadge/SmartBadge.tsx | 12 +- .../AssetPage/UtilityBadge/UtilityBadge.tsx | 4 + .../AssetPage/UtilityBadge/index.ts | 1 + .../WearableDetail/WearableDetail.module.css | 20 ++- .../WearableDetail/WearableDetail.tsx | 14 +- .../AssetProvider/AssetProvider.container.ts | 3 +- .../Campaign/CampaignBadge/CampaignBadge.tsx | 2 +- .../components/GenderBadge/GenderBadge.tsx | 4 +- .../src/modules/translation/locales/en.json | 3 +- .../src/modules/translation/locales/es.json | 3 +- .../src/modules/translation/locales/zh.json | 3 +- .../vendor/decentraland/nft/authApi.ts | 6 +- 31 files changed, 222 insertions(+), 231 deletions(-) create mode 100644 webapp/src/components/AssetPage/AssetUtility/AssetUtility.module.css create mode 100644 webapp/src/components/AssetPage/AssetUtility/AssetUtility.spec.tsx create mode 100644 webapp/src/components/AssetPage/AssetUtility/AssetUtility.tsx create mode 100644 webapp/src/components/AssetPage/AssetUtility/AssetUtility.types.ts create mode 100644 webapp/src/components/AssetPage/AssetUtility/index.ts delete mode 100644 webapp/src/components/AssetPage/IconBadge/IconBadge.css delete mode 100644 webapp/src/components/AssetPage/IconBadge/IconBadge.tsx delete mode 100644 webapp/src/components/AssetPage/IconBadge/IconBadge.types.ts delete mode 100644 webapp/src/components/AssetPage/IconBadge/index.ts create mode 100644 webapp/src/components/AssetPage/LinkedIconBadge/LinkedIconBadge.tsx create mode 100644 webapp/src/components/AssetPage/LinkedIconBadge/LinkedIconBadge.types.ts create mode 100644 webapp/src/components/AssetPage/LinkedIconBadge/index.ts create mode 100644 webapp/src/components/AssetPage/UtilityBadge/UtilityBadge.tsx create mode 100644 webapp/src/components/AssetPage/UtilityBadge/index.ts diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 3290db45ea..487d701f84 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -12,7 +12,7 @@ "@0xsquid/squid-types": "^0.1.29", "@covalenthq/client-sdk": "^0.6.4", "@dcl/crypto": "^3.0.0", - "@dcl/schemas": "^11.4.0", + "@dcl/schemas": "^11.7.0", "@dcl/single-sign-on-client": "^0.1.0", "@dcl/ui-env": "^1.5.0", "@ethersproject/providers": "^5.6.2", @@ -29,7 +29,7 @@ "decentraland-crypto-fetch": "^1.0.3", "decentraland-dapps": "^19.5.3", "decentraland-transactions": "^2.6.0", - "decentraland-ui": "^5.17.1", + "decentraland-ui": "^5.21.0", "ethers": "^5.6.8", "graphql": "^14.7.0", "history": "^4.10.1", @@ -1732,9 +1732,9 @@ "integrity": "sha512-Cg+MoIOn+BYmQV2q8zSFnNYY+GldlnUazwBnfgrq3i66ZxOaZ65h01btd8OUtSAlfWG4VTNIOHDjtKqmuwJNBg==" }, "node_modules/@dcl/schemas": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/@dcl/schemas/-/schemas-11.4.0.tgz", - "integrity": "sha512-pCMENllY9vcl4HS1ta/TpVqjWUov/oa9xab+Ki1iMur48nE5+xXfa7+laCPhWLOKSZEkC59i5S6zQGTSWFPYew==", + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/@dcl/schemas/-/schemas-11.7.0.tgz", + "integrity": "sha512-Gsv4FFnr6vL56k5ozzxH1CcOCzOUHMj602IL5y69q/Iy0rtn+7OF2TckgTDHGeifzakhaVwDOiGFYeJcaMaEXg==", "dependencies": { "ajv": "^8.11.0", "ajv-errors": "^3.0.0", @@ -9279,17 +9279,6 @@ "redux-saga": "^1.1.3" } }, - "node_modules/decentraland-dapps/node_modules/@dcl/schemas": { - "version": "11.4.1-20240412130706.commit-0f2e689", - "resolved": "https://registry.npmjs.org/@dcl/schemas/-/schemas-11.4.1-20240412130706.commit-0f2e689.tgz", - "integrity": "sha512-na9H/+oFTysiy9YppOu+sXu44o+Mn6KRlADINJchd+2yeWCvhNYQLfLtzchAF+ydiBC72xNu90QNkMx4rlv83Q==", - "dependencies": { - "ajv": "^8.11.0", - "ajv-errors": "^3.0.0", - "ajv-keywords": "^5.1.0", - "mitt": "^3.0.1" - } - }, "node_modules/decentraland-dapps/node_modules/@formatjs/intl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.2.1.tgz", @@ -9401,9 +9390,9 @@ } }, "node_modules/decentraland-ui": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/decentraland-ui/-/decentraland-ui-5.17.1.tgz", - "integrity": "sha512-AnRW5wU2z4f2bkHOnHiT1yDurHn8oLOkSLw/Do+hFu0SKpJG7ZyfZCW5QHYquBq65nLwCRStC0CyN9N3CncmiQ==", + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/decentraland-ui/-/decentraland-ui-5.21.0.tgz", + "integrity": "sha512-enRnOEwrJwNksLd0EReDjsEoG2QQq2a/g8hGpInfd6Tc05Ie40VtaOO0/CrzRA0yI82FEDfdxyFRkl5Wj2YTQg==", "dependencies": { "@dcl/schemas": "^11.4.0", "@dcl/ui-env": "^1.4.0", diff --git a/webapp/package.json b/webapp/package.json index dd5f4960af..24179ccbe9 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -7,7 +7,7 @@ "@0xsquid/squid-types": "^0.1.29", "@covalenthq/client-sdk": "^0.6.4", "@dcl/crypto": "^3.0.0", - "@dcl/schemas": "^11.4.0", + "@dcl/schemas": "^11.7.0", "@dcl/single-sign-on-client": "^0.1.0", "@dcl/ui-env": "^1.5.0", "@ethersproject/providers": "^5.6.2", @@ -24,7 +24,7 @@ "decentraland-crypto-fetch": "^1.0.3", "decentraland-dapps": "^19.5.3", "decentraland-transactions": "^2.6.0", - "decentraland-ui": "^5.17.1", + "decentraland-ui": "^5.21.0", "ethers": "^5.6.8", "graphql": "^14.7.0", "history": "^4.10.1", diff --git a/webapp/src/components/AssetPage/AssetUtility/AssetUtility.module.css b/webapp/src/components/AssetPage/AssetUtility/AssetUtility.module.css new file mode 100644 index 0000000000..18e5ccc57d --- /dev/null +++ b/webapp/src/components/AssetPage/AssetUtility/AssetUtility.module.css @@ -0,0 +1,9 @@ +.main :global(.ui.sub.header) { + font-weight: 600; +} + +.main .content { + font-size: 14px; + line-height: 26px; + letter-spacing: 0.2px; +} diff --git a/webapp/src/components/AssetPage/AssetUtility/AssetUtility.spec.tsx b/webapp/src/components/AssetPage/AssetUtility/AssetUtility.spec.tsx new file mode 100644 index 0000000000..ce44f6cf1d --- /dev/null +++ b/webapp/src/components/AssetPage/AssetUtility/AssetUtility.spec.tsx @@ -0,0 +1,22 @@ +import { t } from 'decentraland-dapps/dist/modules/translation' +import { renderWithProviders } from '../../../utils/test' +import { ASSET_UTILITY_CONTENT_DATA_TEST_ID, ASSET_UTILITY_HEADER_DATA_TEST_ID, AssetUtility } from './AssetUtility' +import { Props } from './AssetUtility.types' + +const renderWearableUtility = (props: Partial) => renderWithProviders() + +describe('when rendering the wearable utility component', () => { + let renderedComponent: ReturnType + let utility: string + + beforeEach(() => { + utility = 'This is some utility!' + renderedComponent = renderWearableUtility({ utility }) + }) + + it('should render the utility header and the wearable utility', () => { + const { getByTestId } = renderedComponent + expect(getByTestId(ASSET_UTILITY_HEADER_DATA_TEST_ID).textContent).toEqual(t('global.utility')) + expect(getByTestId(ASSET_UTILITY_CONTENT_DATA_TEST_ID).textContent).toEqual(utility) + }) +}) diff --git a/webapp/src/components/AssetPage/AssetUtility/AssetUtility.tsx b/webapp/src/components/AssetPage/AssetUtility/AssetUtility.tsx new file mode 100644 index 0000000000..a82b2678fc --- /dev/null +++ b/webapp/src/components/AssetPage/AssetUtility/AssetUtility.tsx @@ -0,0 +1,20 @@ +import { t } from 'decentraland-dapps/dist/modules/translation' +import { Header } from 'decentraland-ui/dist/components/Header/Header' +import { Props } from './AssetUtility.types' +import styles from './AssetUtility.module.css' + +export const ASSET_UTILITY_HEADER_DATA_TEST_ID = 'asset-utility-header' +export const ASSET_UTILITY_CONTENT_DATA_TEST_ID = 'asset-utility-content' + +export const AssetUtility = ({ utility }: Props) => { + return ( +
+
+ {t('global.utility')} +
+ + {utility} + +
+ ) +} diff --git a/webapp/src/components/AssetPage/AssetUtility/AssetUtility.types.ts b/webapp/src/components/AssetPage/AssetUtility/AssetUtility.types.ts new file mode 100644 index 0000000000..62dc50b9b6 --- /dev/null +++ b/webapp/src/components/AssetPage/AssetUtility/AssetUtility.types.ts @@ -0,0 +1,3 @@ +export type Props = { + utility: string +} diff --git a/webapp/src/components/AssetPage/AssetUtility/index.ts b/webapp/src/components/AssetPage/AssetUtility/index.ts new file mode 100644 index 0000000000..0832f88871 --- /dev/null +++ b/webapp/src/components/AssetPage/AssetUtility/index.ts @@ -0,0 +1,2 @@ +export * from './AssetUtility' +export * from './AssetUtility.types' diff --git a/webapp/src/components/AssetPage/CategoryBadge/CategoryBadge.tsx b/webapp/src/components/AssetPage/CategoryBadge/CategoryBadge.tsx index 8a1c6c76d2..9d43ba5a43 100644 --- a/webapp/src/components/AssetPage/CategoryBadge/CategoryBadge.tsx +++ b/webapp/src/components/AssetPage/CategoryBadge/CategoryBadge.tsx @@ -1,10 +1,10 @@ import React, { useMemo, useEffect } from 'react' -import { EmoteCategory } from '@dcl/schemas' +import { EmoteCategory, WearableCategory } from '@dcl/schemas' import { t } from 'decentraland-dapps/dist/modules/translation/utils' import { locations } from '../../../modules/routing/locations' import { getSearchSection } from '../../../modules/routing/search' import { BrowseOptions } from '../../../modules/routing/types' -import IconBadge from '../IconBadge' +import IconBadge from '../LinkedIconBadge' import { Props } from './CategoryBadge.types' const CategoryBadge = ({ category, assetType }: Props) => { @@ -27,7 +27,13 @@ const CategoryBadge = ({ category, assetType }: Props) => { } }, [section, category, isEmote]) - return + return ( + + ) } export default React.memo(CategoryBadge) diff --git a/webapp/src/components/AssetPage/EmoteDetail/EmoteDetail.module.css b/webapp/src/components/AssetPage/EmoteDetail/EmoteDetail.module.css index 6c7c8d7e92..6b4c5dd8fe 100644 --- a/webapp/src/components/AssetPage/EmoteDetail/EmoteDetail.module.css +++ b/webapp/src/components/AssetPage/EmoteDetail/EmoteDetail.module.css @@ -48,7 +48,23 @@ color: var(--secondary-text); } +.EmoteDetail .attributesRow { + display: flex; + flex-direction: row; + gap: 10px; + word-wrap: break-word; + word-break: break-all; +} + +.EmoteDetail .attributesColumn { + flex-basis: 100%; +} + @media (max-width: 768px) { + .EmoteDetail .attributesRow { + flex-direction: column; + } + .EmoteDetail .wearableInformationContainer { flex-direction: column; } diff --git a/webapp/src/components/AssetPage/EmoteDetail/EmoteDetail.tsx b/webapp/src/components/AssetPage/EmoteDetail/EmoteDetail.tsx index 8e5b02d1b8..c1c5359467 100644 --- a/webapp/src/components/AssetPage/EmoteDetail/EmoteDetail.tsx +++ b/webapp/src/components/AssetPage/EmoteDetail/EmoteDetail.tsx @@ -8,16 +8,18 @@ import { Section } from '../../../modules/vendor/decentraland' import { AssetImage } from '../../AssetImage' import CampaignBadge from '../../Campaign/CampaignBadge' import TableContainer from '../../Table/TableContainer' +import { AssetUtility } from '../AssetUtility' import { BidsTable } from '../BidsTable' import { BuyNFTBox } from '../BuyNFTBox' import Collection from '../Collection' import { Description } from '../Description' -import IconBadge from '../IconBadge' +import IconBadge from '../LinkedIconBadge' import { ListingsTable } from '../ListingsTable' import OnBack from '../OnBack' import { Owner } from '../Owner' import Title from '../Title' import { TransactionHistory } from '../TransactionHistory' +import { UtilityBadge } from '../UtilityBadge' import { YourOffer } from '../YourOffer' import { Props } from './EmoteDetail.types' import styles from './EmoteDetail.module.css' @@ -96,12 +98,22 @@ const EmoteDetail = ({ nft }: Props) => { text={t(`emote.play_mode.${loop ? 'loop' : 'simple'}`)} href={emoteBadgeHref} /> + {nft.utility ? : null} {emote.hasSound && } {emote.hasGeometry && } - +
+
+ +
+ {nft.utility ? ( +
+ +
+ ) : null} +
diff --git a/webapp/src/components/AssetPage/IconBadge/IconBadge.css b/webapp/src/components/AssetPage/IconBadge/IconBadge.css deleted file mode 100644 index 9c5fc7bb3b..0000000000 --- a/webapp/src/components/AssetPage/IconBadge/IconBadge.css +++ /dev/null @@ -1,142 +0,0 @@ -.IconBadge { - display: inline-flex; - align-items: center; - text-transform: uppercase; - padding: 2px 8px; - border-radius: 5px; - cursor: pointer; - background-color: #37333d; -} - -.IconBadge .text { - font-size: 13px; -} - -.IconBadge .icon { - width: 13px; - height: 13px; - margin-right: 10px; - background-position: center; - background-repeat: no-repeat; -} - -.IconBadge .custom-icon { - margin-right: 10px; -} - -/* Icons */ - -.IconBadge .BaseMale { - background-image: url(../../../images/wearables/MaleIcon.svg); -} - -.IconBadge .BaseFemale { - background-image: url(../../../images/wearables/FemaleIcon.svg); -} - -.IconBadge .Unisex { - background-image: url(../../../images/wearables/UnisexIcon.svg); -} - -.IconBadge .body_shape { - background-image: url(../../../images/wearables/BodyShapeIcon.svg); -} - -.IconBadge .earring { - background-image: url(../../../images/wearables/EarringsIcon.svg); -} - -.IconBadge .eyebrows { - background-image: url(../../../images/wearables/EyebrowIcon.svg); -} - -.IconBadge .eyes { - background-image: url(../../../images/wearables/EyesIcon.svg); -} - -.IconBadge .eyewear { - background-image: url(../../../images/wearables/EyewearIcon.svg); -} - -.IconBadge .facial_hair { - background-image: url(../../../images/wearables/FacilHairIcon.svg); -} - -.IconBadge .feet { - background-image: url(../../../images/wearables/FeetIcon.svg); -} - -.IconBadge .hair { - background-image: url(../../../images/wearables/HairIcon.svg); -} - -.IconBadge .hat { - background-image: url(../../../images/wearables/HatIcon.svg); -} - -.IconBadge .helmet { - background-image: url(../../../images/wearables/HelmetIcon.svg); -} - -.IconBadge .lower_body { - background-image: url(../../../images/wearables/LowerBodyIcon.svg); -} - -.IconBadge .mask { - background-image: url(../../../images/wearables/MaskIcon.svg); -} - -.IconBadge .mouth { - background-image: url(../../../images/wearables/MouthIcon.svg); -} - -.IconBadge .tiara { - background-image: url(../../../images/wearables/TiaraIcon.svg); -} - -.IconBadge .top_head { - background-image: url(../../../images/wearables/TopHeadIcon.svg); -} - -.IconBadge .upper_body { - background-image: url(../../../images/wearables/UpperBodyIcon.svg); -} - -.IconBadge .skin { - background-image: url(../../../images/wearables/SkinIcon.svg); -} - -.IconBadge .hands_wear { - background-size: contain; - background-image: url(../../../images/wearables/HandsIcon.svg); -} - -.IconBadge .play-once { - background-image: url(../../../images/emotes/play-once.svg); - width: 19px; - filter: brightness(0) invert(1); -} - - -.IconBadge .play-loop { - background-image: url(../../../images/emotes/play-loop.svg); - width: 19px; - filter: brightness(0) invert(1); -} - -.IconBadge .sound { - background-image: url(../../../images/emotes/sound.svg); - width: 19px; -} - -.IconBadge .props { - background-image: url(../../../images/emotes/props.svg); - background-size: contain; - width: 19px; -} - -.IconBadge .sparkles { - filter: brightness(0) invert(1); - background-image: url(../../../images/sparkles.svg); - background-size: cover; -} diff --git a/webapp/src/components/AssetPage/IconBadge/IconBadge.tsx b/webapp/src/components/AssetPage/IconBadge/IconBadge.tsx deleted file mode 100644 index ce3837bb3e..0000000000 --- a/webapp/src/components/AssetPage/IconBadge/IconBadge.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react' -import { Link } from 'react-router-dom' -import classNames from 'classnames' -import { Props } from './IconBadge.types' -import './IconBadge.css' - -const IconBadge = ({ icon, text, onClick, href, className, children }: Props) => { - const childrenInt = React.useMemo( - () => ( - <> - {children ? {children} : } - {text} - - ), - [children, icon, text] - ) - - return href ? ( - - {childrenInt} - - ) : ( -
- {childrenInt} -
- ) -} - -export default React.memo(IconBadge) diff --git a/webapp/src/components/AssetPage/IconBadge/IconBadge.types.ts b/webapp/src/components/AssetPage/IconBadge/IconBadge.types.ts deleted file mode 100644 index ba50c1df4f..0000000000 --- a/webapp/src/components/AssetPage/IconBadge/IconBadge.types.ts +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' - -export type Props = { - className?: string - icon?: string - text: string - onClick?: () => void - href?: string - children?: React.ReactNode -} diff --git a/webapp/src/components/AssetPage/IconBadge/index.ts b/webapp/src/components/AssetPage/IconBadge/index.ts deleted file mode 100644 index 762f8aa4ca..0000000000 --- a/webapp/src/components/AssetPage/IconBadge/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import IconBadge from './IconBadge' - -export default IconBadge diff --git a/webapp/src/components/AssetPage/ItemDetail/ItemDetail.module.css b/webapp/src/components/AssetPage/ItemDetail/ItemDetail.module.css index 64442f5eaa..f94023834b 100644 --- a/webapp/src/components/AssetPage/ItemDetail/ItemDetail.module.css +++ b/webapp/src/components/AssetPage/ItemDetail/ItemDetail.module.css @@ -48,6 +48,18 @@ gap: 30px; } +.ItemDetail .attributesRow { + display: flex; + flex-direction: row; + gap: 10px; + word-wrap: break-word; + word-break: break-all; +} + +.ItemDetail .attributesColumn { + flex-basis: 100%; +} + .ItemDetail .basicRow { display: flex; flex-direction: row; @@ -60,8 +72,8 @@ } .ItemDetail .vrmBadge { - background: #FF743933; - color: #FF7439; + background: #ff743933; + color: #ff7439; padding: 3px 6px; height: 24px; font-size: 13px; @@ -88,6 +100,11 @@ } @media (max-width: 768px) { + .ItemDetail .attributesRow { + display: flex; + flex-direction: column; + } + .ItemDetail .assetImageContainer { height: 400px; } @@ -105,7 +122,7 @@ .ItemDetail .basicRow :global(.dcl.stats) { width: 100%; } - + .ItemDetail .basicRow { flex-direction: column; } diff --git a/webapp/src/components/AssetPage/ItemDetail/ItemDetail.tsx b/webapp/src/components/AssetPage/ItemDetail/ItemDetail.tsx index d17c736a7e..449c6aa35e 100644 --- a/webapp/src/components/AssetPage/ItemDetail/ItemDetail.tsx +++ b/webapp/src/components/AssetPage/ItemDetail/ItemDetail.tsx @@ -13,11 +13,12 @@ import { Section } from '../../../modules/vendor/decentraland' import { AssetImage } from '../../AssetImage' import CampaignBadge from '../../Campaign/CampaignBadge' import GenderBadge from '../../GenderBadge' +import { AssetUtility } from '../AssetUtility' import { BestBuyingOption } from '../BestBuyingOption' import CategoryBadge from '../CategoryBadge' import Collection from '../Collection' import { Description } from '../Description' -import IconBadge from '../IconBadge' +import IconBadge from '../LinkedIconBadge' import ListingsTableContainer from '../ListingsTableContainer/ListingsTableContainer' import OnBack from '../OnBack' import { Owner } from '../Owner' @@ -25,6 +26,7 @@ import { RequiredPermissions } from '../RequiredPermissions' import SmartBadge from '../SmartBadge' import Title from '../Title' import { TransactionHistory } from '../TransactionHistory' +import { UtilityBadge } from '../UtilityBadge' import { Props } from './ItemDetail.types' import styles from './ItemDetail.module.css' @@ -132,11 +134,21 @@ const ItemDetail = ({ item }: Props) => { } /> )} + {item.utility && }
- +
+
+ +
+ {item.utility ? ( +
+ +
+ ) : null} +
0 && item.isOnSale diff --git a/webapp/src/components/AssetPage/LinkedIconBadge/LinkedIconBadge.tsx b/webapp/src/components/AssetPage/LinkedIconBadge/LinkedIconBadge.tsx new file mode 100644 index 0000000000..e29540b887 --- /dev/null +++ b/webapp/src/components/AssetPage/LinkedIconBadge/LinkedIconBadge.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import { Link } from 'react-router-dom' +import { IconBadge } from 'decentraland-ui/dist/components/IconBadge/IconBadge' +import { Props } from './LinkedIconBadge.types' + +const LinkedIconBadge = (props: Props) => { + const { href, ...rest } = props + + return href ? ( + + + + ) : ( + + ) +} + +export default React.memo(LinkedIconBadge) diff --git a/webapp/src/components/AssetPage/LinkedIconBadge/LinkedIconBadge.types.ts b/webapp/src/components/AssetPage/LinkedIconBadge/LinkedIconBadge.types.ts new file mode 100644 index 0000000000..401af39c29 --- /dev/null +++ b/webapp/src/components/AssetPage/LinkedIconBadge/LinkedIconBadge.types.ts @@ -0,0 +1,2 @@ +import { Props as IconBadgeProps } from 'decentraland-ui/dist/components/IconBadge/IconBadge.types' +export type Props = IconBadgeProps & { href?: string } diff --git a/webapp/src/components/AssetPage/LinkedIconBadge/index.ts b/webapp/src/components/AssetPage/LinkedIconBadge/index.ts new file mode 100644 index 0000000000..d6dd55a207 --- /dev/null +++ b/webapp/src/components/AssetPage/LinkedIconBadge/index.ts @@ -0,0 +1,4 @@ +import LinkedIconBadge from './LinkedIconBadge' + +export * from './LinkedIconBadge.types' +export default LinkedIconBadge diff --git a/webapp/src/components/AssetPage/SmartBadge/SmartBadge.tsx b/webapp/src/components/AssetPage/SmartBadge/SmartBadge.tsx index 07901ff96b..746a414587 100644 --- a/webapp/src/components/AssetPage/SmartBadge/SmartBadge.tsx +++ b/webapp/src/components/AssetPage/SmartBadge/SmartBadge.tsx @@ -1,10 +1,9 @@ import React, { useMemo } from 'react' import classNames from 'classnames' import { t } from 'decentraland-dapps/dist/modules/translation/utils' -import { SmartIcon } from 'decentraland-ui' import { locations } from '../../../modules/routing/locations' import { Section } from '../../../modules/vendor/decentraland' -import IconBadge from '../IconBadge' +import LinkedIconBadge from '../LinkedIconBadge' import { Props } from './SmartBadge.types' import './SmartBadge.css' @@ -20,9 +19,12 @@ const SmartBadge = ({ assetType, clickable = true }: Props) => { ) return ( - - - + ) } diff --git a/webapp/src/components/AssetPage/UtilityBadge/UtilityBadge.tsx b/webapp/src/components/AssetPage/UtilityBadge/UtilityBadge.tsx new file mode 100644 index 0000000000..b816fce175 --- /dev/null +++ b/webapp/src/components/AssetPage/UtilityBadge/UtilityBadge.tsx @@ -0,0 +1,4 @@ +import { t } from 'decentraland-dapps/dist/modules/translation' +import { IconBadge } from 'decentraland-ui/dist/components/IconBadge/IconBadge' + +export const UtilityBadge = () => diff --git a/webapp/src/components/AssetPage/UtilityBadge/index.ts b/webapp/src/components/AssetPage/UtilityBadge/index.ts new file mode 100644 index 0000000000..e6dea3eb4f --- /dev/null +++ b/webapp/src/components/AssetPage/UtilityBadge/index.ts @@ -0,0 +1 @@ +export * from './UtilityBadge' diff --git a/webapp/src/components/AssetPage/WearableDetail/WearableDetail.module.css b/webapp/src/components/AssetPage/WearableDetail/WearableDetail.module.css index d7f11679f2..7f82a43bfa 100644 --- a/webapp/src/components/AssetPage/WearableDetail/WearableDetail.module.css +++ b/webapp/src/components/AssetPage/WearableDetail/WearableDetail.module.css @@ -47,8 +47,8 @@ } .WearableDetail .vrmBadge { - background: #FF743933; - color: #FF7439; + background: #ff743933; + color: #ff7439; padding: 3px 6px; height: 24px; font-size: 13px; @@ -57,7 +57,23 @@ text-transform: uppercase; } +.WearableDetail .attributesRow { + display: flex; + flex-direction: row; + gap: 10px; + word-wrap: break-word; + word-break: break-all; +} + +.WearableDetail .attributesColumn { + flex-basis: 100%; +} + @media (max-width: 768px) { + .WearableDetail .attributesRow { + flex-direction: column; + } + .WearableDetail .wearableInformationContainer { gap: 16px; } diff --git a/webapp/src/components/AssetPage/WearableDetail/WearableDetail.tsx b/webapp/src/components/AssetPage/WearableDetail/WearableDetail.tsx index 6347b34242..f34f2548b3 100644 --- a/webapp/src/components/AssetPage/WearableDetail/WearableDetail.tsx +++ b/webapp/src/components/AssetPage/WearableDetail/WearableDetail.tsx @@ -9,6 +9,7 @@ import { AssetImage } from '../../AssetImage' import CampaignBadge from '../../Campaign/CampaignBadge' import GenderBadge from '../../GenderBadge' import TableContainer from '../../Table/TableContainer' +import { AssetUtility } from '../AssetUtility' import { BidsTable } from '../BidsTable' import { BuyNFTBox } from '../BuyNFTBox' import CategoryBadge from '../CategoryBadge' @@ -21,6 +22,7 @@ import { RequiredPermissions } from '../RequiredPermissions' import SmartBadge from '../SmartBadge' import Title from '../Title' import { TransactionHistory } from '../TransactionHistory' +import { UtilityBadge } from '../UtilityBadge' import { YourOffer } from '../YourOffer' import { Props } from './WearableDetail.types' import styles from './WearableDetail.module.css' @@ -74,6 +76,7 @@ const WearableDetail = ({ nft }: Props) => { {wearable.isSmart ? : null} + {nft.utility ? : null} {(nft.entity?.metadata as Wearable)?.data?.blockVrmExport && ( { )}
- +
+
+ +
+ {nft.utility ? ( +
+ +
+ ) : null} +
{wearable.isSmart ? : null}
diff --git a/webapp/src/components/AssetProvider/AssetProvider.container.ts b/webapp/src/components/AssetProvider/AssetProvider.container.ts index 859ed0dac2..3f9d44daf5 100644 --- a/webapp/src/components/AssetProvider/AssetProvider.container.ts +++ b/webapp/src/components/AssetProvider/AssetProvider.container.ts @@ -88,7 +88,8 @@ const mapState = (state: RootState, ownProps: OwnProps): MapStateProps => { asset, rental, order, - isLoading: !asset ? isLoading : isFetchingRequiredPermissions(state, asset.id) || isFetchingVideoHash(state, asset.id), + isLoading: + isLoading || !!(asset && isFetchingRequiredPermissions(state, asset.id)) || !!(asset && isFetchingVideoHash(state, asset.id)), isLoadingFeatureFlags: isLoadingType(getIsLoadingFeatureFlags(state), FETCH_APPLICATION_FEATURES_REQUEST), isLandOrEstate, error, diff --git a/webapp/src/components/Campaign/CampaignBadge/CampaignBadge.tsx b/webapp/src/components/Campaign/CampaignBadge/CampaignBadge.tsx index 49482cad82..35cd15a215 100644 --- a/webapp/src/components/Campaign/CampaignBadge/CampaignBadge.tsx +++ b/webapp/src/components/Campaign/CampaignBadge/CampaignBadge.tsx @@ -6,7 +6,7 @@ import { SortBy } from '../../../modules/routing/types' import { VendorName } from '../../../modules/vendor' import * as decentraland from '../../../modules/vendor/decentraland' import { builderAPI } from '../../../modules/vendor/decentraland/builder/api' -import IconBadge from '../../AssetPage/IconBadge' +import IconBadge from '../../AssetPage/LinkedIconBadge' import { CAMPAIGN_TAG } from '../config' import { Props } from './CampaignBadge.types' diff --git a/webapp/src/components/GenderBadge/GenderBadge.tsx b/webapp/src/components/GenderBadge/GenderBadge.tsx index bd2fe35b68..56b5ac9471 100644 --- a/webapp/src/components/GenderBadge/GenderBadge.tsx +++ b/webapp/src/components/GenderBadge/GenderBadge.tsx @@ -4,7 +4,7 @@ import { BodyShape, WearableGender } from '@dcl/schemas' import { t } from 'decentraland-dapps/dist/modules/translation/utils' import { isGender, isUnisex as getIsUnisex } from '../../modules/nft/utils' import { locations } from '../../modules/routing/locations' -import IconBadge from '../AssetPage/IconBadge' +import IconBadge from '../AssetPage/LinkedIconBadge' import { Props } from './GenderBadge.types' import styles from './GenderBadge.module.css' @@ -26,7 +26,7 @@ const GenderBadge = ({ bodyShapes, withText, assetType, section }: Props) => { [assetType, section, isUnisex, isGenderBodyShape] ) - const icon = isUnisex ? 'Unisex' : bodyShapes[0] + const icon = isUnisex ? 'Unisex' : bodyShapes[0].endsWith('BaseMale') ? 'BaseMale' : 'BaseFemale' return withText ? ( - Array.isArray(value) ? value.forEach(aValue => queryParams.append(key, aValue)) : queryParams.append(key, value) + Array.isArray(value) + ? value.filter(v => v !== undefined).forEach(aValue => queryParams.append(key, aValue)) + : value !== undefined + ? queryParams.append(key, value) + : null ) } const response: NFTResponse = await this.fetch(`/v1/nfts?${queryParams.toString()}`)