Browse Source

Merge branch 'dev'

Artem 1 year ago
parent
commit
0ae8ccf050
100 changed files with 1410 additions and 1443 deletions
  1. 1 1
      ci/nginx/default.conf.template
  2. 52 8
      docs/operator-guide.md
  3. 1 1
      package.json
  4. 2 2
      packages/atlas-meta-server/src/tags.ts
  5. 4 4
      packages/atlas/atlas.config.yml
  6. 20 2
      packages/atlas/src/MainLayout.tsx
  7. 2 3
      packages/atlas/src/api/client/cache.ts
  8. 0 74
      packages/atlas/src/api/client/index.ts
  9. 7 3
      packages/atlas/src/api/hooks/channel.ts
  10. 2 1
      packages/atlas/src/api/queries/__generated__/baseTypes.generated.ts
  11. 0 1
      packages/atlas/src/api/queries/__generated__/bids.generated.tsx
  12. 0 15
      packages/atlas/src/api/queries/__generated__/channels.generated.tsx
  13. 0 4
      packages/atlas/src/api/queries/__generated__/comments.generated.tsx
  14. 0 12
      packages/atlas/src/api/queries/__generated__/featured.generated.tsx
  15. 0 69
      packages/atlas/src/api/queries/__generated__/fragments.generated.tsx
  16. 0 3
      packages/atlas/src/api/queries/__generated__/memberships.generated.tsx
  17. 0 57
      packages/atlas/src/api/queries/__generated__/nfts.generated.tsx
  18. 0 90
      packages/atlas/src/api/queries/__generated__/notifications.generated.tsx
  19. 0 4
      packages/atlas/src/api/queries/__generated__/transactionEvents.generated.tsx
  20. 0 60
      packages/atlas/src/api/queries/__generated__/videos.generated.tsx
  21. 0 1
      packages/atlas/src/api/queries/fragments.graphql
  22. 1 1
      packages/atlas/src/components/ActionBar/ActionBar.tsx
  23. 36 0
      packages/atlas/src/components/AssetImage/AssetImage.tsx
  24. 1 0
      packages/atlas/src/components/AssetImage/index.ts
  25. 19 0
      packages/atlas/src/components/AssetVideo/AssetVideo.tsx
  26. 1 1
      packages/atlas/src/components/Avatar/Avatar.stories.tsx
  27. 2 22
      packages/atlas/src/components/Avatar/Avatar.styles.ts
  28. 11 45
      packages/atlas/src/components/Avatar/Avatar.tsx
  29. 4 4
      packages/atlas/src/components/Avatar/AvatarGroup.stories.tsx
  30. 6 6
      packages/atlas/src/components/Avatar/AvatarGroup.tsx
  31. 1 0
      packages/atlas/src/components/Fee/Fee.tsx
  32. 3 6
      packages/atlas/src/components/MembershipInfo/MembershipInfo.tsx
  33. 3 1
      packages/atlas/src/components/MinimizedPlayer/MinimizedPlayer.tsx
  34. 20 17
      packages/atlas/src/components/NftCarousel/components/MarketplaceCarouselCard/NftCarouselDetails.tsx
  35. 130 12
      packages/atlas/src/components/NumberFormat/NumberFormat.tsx
  36. 1 1
      packages/atlas/src/components/OutputPill/OutputPill.stories.tsx
  37. 3 3
      packages/atlas/src/components/OutputPill/OutputPill.tsx
  38. 1 1
      packages/atlas/src/components/OwnerPill/OwnerPill.tsx
  39. 8 4
      packages/atlas/src/components/Searchbar/SearchBox/Result.tsx
  40. 9 0
      packages/atlas/src/components/Searchbar/Searchbar.styles.ts
  41. 4 4
      packages/atlas/src/components/Section/Section.stories.tsx
  42. 1 1
      packages/atlas/src/components/Section/SectionHeader/SectionHeader.stories.tsx
  43. 3 0
      packages/atlas/src/components/Table/Table.styles.ts
  44. 11 14
      packages/atlas/src/components/TablePaymentsHistory/TablePaymentsHistory.tsx
  45. 4 2
      packages/atlas/src/components/TopSellingChannelsTable/TopSellingChannelsTable.tsx
  46. 1 1
      packages/atlas/src/components/WidgetTile/WidgetTile.styles.ts
  47. 5 1
      packages/atlas/src/components/_auth/SignInModal/SignInModal.tsx
  48. 1 1
      packages/atlas/src/components/_auth/SignInModal/SignInSteps/SignInModalMembershipStep.tsx
  49. 1 1
      packages/atlas/src/components/_channel/ChannelCard/ChannelCard.tsx
  50. 2 2
      packages/atlas/src/components/_channel/ChannelCover/ChannelCover.stories.tsx
  51. 2 1
      packages/atlas/src/components/_channel/ChannelCover/ChannelCover.styles.ts
  52. 10 17
      packages/atlas/src/components/_channel/ChannelCover/ChannelCover.tsx
  53. 1 1
      packages/atlas/src/components/_channel/ChannelLink/ChannelLink.tsx
  54. 1 1
      packages/atlas/src/components/_channel/ChannelWithVideos/ChannelWithVideos.tsx
  55. 4 4
      packages/atlas/src/components/_channel/CollectorsBox/CollectorsBox.stories.tsx
  56. 1 1
      packages/atlas/src/components/_channel/CollectorsBox/CollectorsBox.tsx
  57. 3 3
      packages/atlas/src/components/_comments/Comment/Comment.tsx
  58. 3 3
      packages/atlas/src/components/_comments/Comment/InternalComment.tsx
  59. 2 2
      packages/atlas/src/components/_comments/CommentEditHistory/CommentEditHistory.tsx
  60. 4 4
      packages/atlas/src/components/_comments/CommentRow/CommentRow.tsx
  61. 3 3
      packages/atlas/src/components/_comments/CommentSnapshot/CommentSnaphsot.tsx
  62. 18 18
      packages/atlas/src/components/_inputs/ComboBox/ComboBox.stories.tsx
  63. 2 1
      packages/atlas/src/components/_inputs/ComboBox/ComboBox.styles.ts
  64. 4 2
      packages/atlas/src/components/_inputs/ComboBox/ComboBox.tsx
  65. 1 1
      packages/atlas/src/components/_inputs/Input/Input.stories.tsx
  66. 4 4
      packages/atlas/src/components/_inputs/MemberComboBox/MemberComboBox.tsx
  67. 2 2
      packages/atlas/src/components/_inputs/SubtitlesBox/SubtitlesBox.tsx
  68. 1 1
      packages/atlas/src/components/_navigation/SidenavViewer/FollowedChannels.tsx
  69. 5 5
      packages/atlas/src/components/_navigation/TopbarStudio/TopbarStudio.tsx
  70. 3 3
      packages/atlas/src/components/_navigation/TopbarViewer/TopbarViewer.tsx
  71. 3 3
      packages/atlas/src/components/_nft/NftCard/Members.tsx
  72. 1 0
      packages/atlas/src/components/_nft/NftTile/NftTile.styles.ts
  73. 2 1
      packages/atlas/src/components/_nft/NftTile/NftTile.tsx
  74. 1 0
      packages/atlas/src/components/_nft/NftTile/NftTileDetails.styles.ts
  75. 14 6
      packages/atlas/src/components/_nft/NftTile/NftTileDetails.tsx
  76. 7 7
      packages/atlas/src/components/_nft/NftTileViewer/NftTileViewer.tsx
  77. 5 61
      packages/atlas/src/components/_nft/NftWidget/NftHistory.styles.ts
  78. 20 44
      packages/atlas/src/components/_nft/NftWidget/NftHistory.tsx
  79. 10 8
      packages/atlas/src/components/_nft/NftWidget/NftWidget.hooks.ts
  80. 46 48
      packages/atlas/src/components/_nft/NftWidget/NftWidget.styles.ts
  81. 72 542
      packages/atlas/src/components/_nft/NftWidget/NftWidget.tsx
  82. 41 0
      packages/atlas/src/components/_nft/NftWidget/NftWidget.types.ts
  83. 54 0
      packages/atlas/src/components/_nft/NftWidget/NftWidgetContent.styles.ts
  84. 542 0
      packages/atlas/src/components/_nft/NftWidget/NftWidgetContent.tsx
  85. 3 3
      packages/atlas/src/components/_notifications/NotificationTile/NotificationTile.tsx
  86. 14 14
      packages/atlas/src/components/_overlays/AcceptBidDialog/AcceptBidList.tsx
  87. 1 1
      packages/atlas/src/components/_overlays/ImageCropModal/ImageCropModal.stories.tsx
  88. 6 3
      packages/atlas/src/components/_overlays/MemberDropdown/MemberDropdown.tsx
  89. 3 3
      packages/atlas/src/components/_overlays/MemberDropdown/MemberDropdownList.tsx
  90. 22 10
      packages/atlas/src/components/_overlays/MemberDropdown/MemberDropdownNav.tsx
  91. 2 2
      packages/atlas/src/components/_overlays/SendTransferDialogs/SendFundsDialog.tsx
  92. 3 3
      packages/atlas/src/components/_overlays/SendTransferDialogs/WithdrawFundsDialog.tsx
  93. 4 2
      packages/atlas/src/components/_video/BackgroundVideoPlayer/BackgroundVideoPlayer.styles.ts
  94. 6 4
      packages/atlas/src/components/_video/BackgroundVideoPlayer/BackgroundVideoPlayer.tsx
  95. 2 2
      packages/atlas/src/components/_video/VideoHero/VideoHero.tsx
  96. 3 3
      packages/atlas/src/components/_video/VideoPlayer/VideoOverlay.tsx
  97. 2 1
      packages/atlas/src/components/_video/VideoPlayer/VideoOverlays/EndingOverlay.styles.ts
  98. 8 8
      packages/atlas/src/components/_video/VideoPlayer/VideoOverlays/EndingOverlay.tsx
  99. 1 1
      packages/atlas/src/components/_video/VideoPlayer/VideoPlayer.stories.tsx
  100. 54 20
      packages/atlas/src/components/_video/VideoPlayer/VideoPlayer.tsx

+ 1 - 1
ci/nginx/default.conf.template

@@ -17,7 +17,7 @@ server {
     server_tokens off;
     server_tokens off;
 
 
     location / {
     location / {
-        if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
+        if ($http_user_agent ~* "googlebot|YandexBot|baiduspider|twitterbot|facebookexternalhit|discordbot|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|Rocket.Chat|Minds|Taringa|redditbot") {
             proxy_pass http://${META_SERVER_HOSTNAME};
             proxy_pass http://${META_SERVER_HOSTNAME};
             break;
             break;
         }
         }

+ 52 - 8
docs/operator-guide.md

@@ -167,14 +167,60 @@ joystream-cli content:createVideoCategory "My category" "My category description
 
 
 Once you run the above command, you can use the query above with a `orderBy: createdAt_DESC` argument to get the ID of the newly created category. You can then add it to the `content.categories` config entry.
 Once you run the above command, you can use the query above with a `orderBy: createdAt_DESC` argument to get the ID of the newly created category. You can then add it to the `content.categories` config entry.
 
 
-#### YouTube Partner Program
+In order to enable YPP content in atlas, `googleConsoleClientId` variable needs to be provided. You can read more about it [here](https://developers.google.com/identity/gsi/web/guides/get-google-api-clientid).
 
 
-All the YPP (YouTube Partner Program) parameters could be found in `atlas.config.yml` file located in `packages/atlas` directory.
-`features.ypp` section contains all the necessary params for setting up [youtube-synch](https://github.com/Joystream/youtube-synch/) and customizing user's rewards.
+#### Environment variables
 
 
-Once youtube-synch is setup, you'll need to provide its API URL in `youtubeSyncApiUrl` variable.
+Atlas uses environment variables, so you can customize it for your specific needs. `.env` file is located in `/packages/atlas/src` directory.
+Below is the list of all the variables used by Atlas with a short description:
 
 
-In order to enable YPP content in atlas, `googleConsoleClientId` variable needs to be provided. You can read more about it [here](https://developers.google.com/identity/gsi/web/guides/get-google-api-clientid).
+**Required:**
+
+`VITE_ENV` - used for making a production build.
+
+`VITE_ENV_SELECTION_ENABLED` - enables environment selection dropdown in the admin panel. Recommended to be set to `false` in production.
+
+`VITE_AVATAR_SERVICE_URL` - URL for avatar service - used to upload member's avatar.
+
+`VITE_HCAPTCHA_SITE_KEY` - hCaptcha site key. See [Captcha](#captcha) section for more info.
+
+`VITE_{environment}_ORION_URL` - Orion URL. See [Orion](#orion) section for more info.
+
+`VITE_{environment}_QUERY_NODE_SUBSCRIPTION_URL` - Orion's Query Node URL. See [Query Node](#query-node) section for more info.
+
+`VITE_{environment}_NODE_URL` - RPC Node URL. See [RPC Node](#rpc-node) section for more info.
+
+`VITE_{environment}_FAUCET_URL` - Faucet URL. See [Member Faucet](#member-faucet) section for more info.
+
+**Optional**:
+
+`VITE_DEFAULT_DATA_ENV` - if `VITE_ENV` is set to `true`, atlas will use `VITE_PRODUCTION_` URLs. Changing this variable can overwrite this.
+
+`VITE_FORCE_MAINTENANCE` - Setting this to `true` will enable the maintenance mode. Orion has its own KillSwitch mechanism which will also enable maintenance mode for Atlas, but this variable can be used when Orion is down or temporarily unavailable.
+
+`VITE_GEOLOCATION_SERVICE_URL` - URL for geolocation service - used to determine user's location to find the closest distributor. See [Geolocation service](#geolocation-service) section for more info.
+
+`VITE_APP_ID` - id of the app for wrapping metadata. You can receive an Id by [creating an app](https://github.com/Joystream/joystream/tree/master/cli#joystream-cli-appscreateapp) in joystream-cli.
+
+`VITE_APP_NAME` - name of the app for wrapping metadata.
+
+`VITE_GOOGLE_CONSOLE_CLIENT_ID` - ID of your Google console client. Used to enable the [youtube-sync](https://github.com/Joystream/youtube-synch) service for YPP.
+
+`VITE_YOUTUBE_SYNC_API_URL` - URL of your youtube-sync instance.
+
+`VITE_YOUTUBE_COLLABORATOR_MEMBER_ID` - The collaborator can add videos to a channel for a user. Every time a user signs up with the program, we're sending the `updateChannel` extrinsic and adding a collaborator to that channel. The collaborator is defined on the youtube-synch backend and needs to be the same in the front-end.
+
+`VITE_GA_ID` - Google Analytics ID. Used to enable Google Analytics.
+
+`VITE_SEGMENT_ID` - Segment ID. Used to enable Segment analytics tool.
+
+`VITE_SENTRY_DSN` - Sentry DSN. Used to enable Sentry error tracking.
+
+`VITE_LIVESESSION_ID` - LiveSession ID. Used to enable LiveSession analytics. See [Livesession](#livesession) section for more info.
+
+`VITE_OPTIMIZE_ID` - Optimize ID. Used to enable Google Optimize.
+
+`VITE_USERSNAP_ID` - Usersnap ID. Used to enable Usersnap.
 
 
 #### Terms of Service, Copyright Policy and Privacy Policy
 #### Terms of Service, Copyright Policy and Privacy Policy
 
 
@@ -200,9 +246,7 @@ Orion is the main backend service for Atlas - providing indexed blockchain data
 
 
 ### Query Node
 ### Query Node
 
 
-Query Node (QN) is a service that processes blockchain events and stores them in a database. Orion proxies requests from Atlas to QN, so it will need a QN URL provided for it to work. You can find more info about QN in [its repo](https://github.com/Joystream/joystream/tree/master/query-node). As a gateway operator you probably want to run your own QN, but it also should be fine to rely on a publicly available instance, like `https://query.joystream.org/graphql`.
-
-Atlas uses Websocket connection to QN to receive real-time updates about QN state and to properly update the UI. Endpoint for this connection must be passed as the `VITE_PRODUCTION_QUERY_NODE_SUBSCRIPTION_URL` environment variable.
+Query Node (QN) is a service that processes blockchain events and stores them in a database. Orion v2 has it's own Query Node included by default, so you don't need to run it separately. However, if you are running Orion v1, you will need to run QN separately. You can find more information about QN in [its repo](https://github.com/Joystream/joystream/tree/master/query-node).
 
 
 ### RPC Node
 ### RPC Node
 
 

+ 1 - 1
package.json

@@ -80,7 +80,7 @@
     "blake3": "patch:blake3@npm:2.1.7#.yarn/patches/blake3-npm-2.1.7-7bf40c44b4"
     "blake3": "patch:blake3@npm:2.1.7#.yarn/patches/blake3-npm-2.1.7-7bf40c44b4"
   },
   },
   "engines": {
   "engines": {
-    "node": "^16"
+    "node": "^18"
   },
   },
   "packageManager": "yarn@3.2.1"
   "packageManager": "yarn@3.2.1"
 }
 }

+ 2 - 2
packages/atlas-meta-server/src/tags.ts

@@ -54,7 +54,7 @@ export const generateCommonMetaTags = (
 
 
 export const generateVideoMetaTags = (
 export const generateVideoMetaTags = (
   video: BasicVideoFieldsFragment,
   video: BasicVideoFieldsFragment,
-  thumbnailUrl: string,
+  thumbnailUrls: string[],
   appName: string,
   appName: string,
   baseAppUrl: string,
   baseAppUrl: string,
   twitterId?: string
   twitterId?: string
@@ -67,7 +67,7 @@ export const generateVideoMetaTags = (
     videoUrl,
     videoUrl,
     videoTitle,
     videoTitle,
     video.description || videoTitle,
     video.description || videoTitle,
-    thumbnailUrl,
+    thumbnailUrls[0],
     twitterId
     twitterId
   )
   )
 
 

+ 4 - 4
packages/atlas/atlas.config.yml

@@ -12,7 +12,7 @@ general:
   joystreamDiscordUrl: 'https://discord.gg/DE9UN3YpRP' # URL for Joystream Discord - used for support when errors occur
   joystreamDiscordUrl: 'https://discord.gg/DE9UN3YpRP' # URL for Joystream Discord - used for support when errors occur
   appContentFocus: 'web3 & crypto' # Content focus of given app. Provide a string, for example `web & crypto` or `sport`
   appContentFocus: 'web3 & crypto' # Content focus of given app. Provide a string, for example `web & crypto` or `sport`
 storage:
 storage:
-  assetResponseTimeout: 20000 # Timeout for asset response in ms - after this timeout, different distributor will be tried
+  assetResponseTimeout: 2_000 # Timeout for asset response in ms - after this timeout, different distributor will be tried
   assetUploadStatusPollingInterval: 2000 # Interval for polling asset upload status in ms - polling begins once asset is uploaded and is finished once QN reports the asset as accepted
   assetUploadStatusPollingInterval: 2000 # Interval for polling asset upload status in ms - polling begins once asset is uploaded and is finished once QN reports the asset as accepted
   uploadProcessingTimeout: 60000 # Timeout for processing uploaded asset in ms - after this timeout, upload will be considered failed
   uploadProcessingTimeout: 60000 # Timeout for processing uploaded asset in ms - after this timeout, upload will be considered failed
   minimumDistributorRefetchTime: 1000 # Minimum time before refetching distributors list in ms - refetching is done if certain bag is not found on any distributor
   minimumDistributorRefetchTime: 1000 # Minimum time before refetching distributors list in ms - refetching is done if certain bag is not found on any distributor
@@ -24,7 +24,7 @@ storage:
 
 
 joystream:
 joystream:
   tokenTicker: 'JOY' # Ticker for the token used in the app
   tokenTicker: 'JOY' # Ticker for the token used in the app
-  tokenPriceFeedUrl: null # URL for the token price feed - used to display token price in the app
+  tokenPriceFeedUrl: 'https://status.joystream.org/price' # URL for the token price feed - used to display token price in the app
   alternativeNodes:
   alternativeNodes:
     - name: 'Jsgenesis (Europe/UK)'
     - name: 'Jsgenesis (Europe/UK)'
       url: 'wss://testnet-rpc-3-uk.joystream.org'
       url: 'wss://testnet-rpc-3-uk.joystream.org'
@@ -131,7 +131,7 @@ features:
 
 
         ## Other ways Joystream Channels can get rewards
         ## Other ways Joystream Channels can get rewards
 
 
-        Joystream DAO operating model encapsulates rewards for Joystream channels paid out outside of the Youtube Partnership Program. Gleev Operator, JS Genesis AS has no responsibility or control over such mechanisms and they are listed below.
+        Joystream DAO operating model encapsulates rewards for Joystream channels paid out outside of the YouTube Partnership Program. Gleev Operator, JS Genesis AS has no responsibility or control over such mechanisms and they are listed below.
 
 
         1. Payout Proposal to Channels by DAO Council.
         1. Payout Proposal to Channels by DAO Council.
         2. Direct Payment from DAO Working Group Budget by WG Lead.
         2. Direct Payment from DAO Working Group Budget by WG Lead.
@@ -586,7 +586,7 @@ legal:
 
 
     Joystream Standard License is the default setting for all uploads. It allows creators to retain all ownership over their content, which published on Joystream network storage nodes, while giving any App built and operated by JS Genesis, Joystream DAO or external operators that work with Joystream Blockchain to broadcast this content.
     Joystream Standard License is the default setting for all uploads. It allows creators to retain all ownership over their content, which published on Joystream network storage nodes, while giving any App built and operated by JS Genesis, Joystream DAO or external operators that work with Joystream Blockchain to broadcast this content.
 
 
-    For content automatically synced from Youtube via Youtube Partnership Programme, YouTube Standard License is substituted by Joystream Standard License. 
+    For content automatically synced from YouTube via YouTube Partnership Program, YouTube Standard License is substituted by Joystream Standard License. 
 
 
     2. CCO
     2. CCO
 
 

+ 20 - 2
packages/atlas/src/MainLayout.tsx

@@ -1,11 +1,12 @@
 import loadable from '@loadable/component'
 import loadable from '@loadable/component'
 import { FC, useEffect, useRef, useState } from 'react'
 import { FC, useEffect, useRef, useState } from 'react'
-import { Route, Routes, useLocation, useNavigationType } from 'react-router-dom'
+import { Route, Routes, useLocation, useNavigationType, useSearchParams } from 'react-router-dom'
 
 
 import { StudioLoading } from '@/components/_loaders/StudioLoading'
 import { StudioLoading } from '@/components/_loaders/StudioLoading'
 import { CookiePopover } from '@/components/_overlays/CookiePopover'
 import { CookiePopover } from '@/components/_overlays/CookiePopover'
 import { atlasConfig } from '@/config'
 import { atlasConfig } from '@/config'
 import { BASE_PATHS, absoluteRoutes } from '@/config/routes'
 import { BASE_PATHS, absoluteRoutes } from '@/config/routes'
+import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics'
 import { transitions } from '@/styles'
 import { transitions } from '@/styles'
 import { RoutingState } from '@/types/routing'
 import { RoutingState } from '@/types/routing'
 import { isBrowserOutdated } from '@/utils/browser'
 import { isBrowserOutdated } from '@/utils/browser'
@@ -40,6 +41,7 @@ const LoadablePlaygroundLayout = loadable(() => import('./views/playground/Playg
 export const MainLayout: FC = () => {
 export const MainLayout: FC = () => {
   const scrollPosition = useRef<number>(0)
   const scrollPosition = useRef<number>(0)
   const location = useLocation()
   const location = useLocation()
+  const [searchParams] = useSearchParams()
   const navigationType = useNavigationType()
   const navigationType = useNavigationType()
   const [cachedLocation, setCachedLocation] = useState(location)
   const [cachedLocation, setCachedLocation] = useState(location)
   const locationState = location.state as RoutingState
   const locationState = location.state as RoutingState
@@ -54,11 +56,24 @@ export const MainLayout: FC = () => {
     },
     },
     onExitClick: () => closeDialog(),
     onExitClick: () => closeDialog(),
   })
   })
+  const { trackPageView } = useSegmentAnalytics()
 
 
   useEffect(() => {
   useEffect(() => {
+    // had to include this timeout to make sure the page title is updated
+    const trackRequestTimeout = setTimeout(
+      () =>
+        trackPageView(
+          document.title,
+          'viewer',
+          (location.pathname === absoluteRoutes.viewer.ypp() && searchParams.get('referrer')) || undefined
+        ),
+      1000
+    )
+
     if (!atlasConfig.analytics.sentry?.dsn) {
     if (!atlasConfig.analytics.sentry?.dsn) {
       return
       return
     }
     }
+
     const stopReplay = async () => await SentryLogger.replay?.stop()
     const stopReplay = async () => await SentryLogger.replay?.stop()
 
 
     if (location.pathname === absoluteRoutes.viewer.ypp()) {
     if (location.pathname === absoluteRoutes.viewer.ypp()) {
@@ -70,7 +85,10 @@ export const MainLayout: FC = () => {
         stopReplay()
         stopReplay()
       }
       }
     }
     }
-  }, [location.pathname])
+    return () => {
+      clearTimeout(trackRequestTimeout)
+    }
+  }, [location.pathname, trackPageView, searchParams])
 
 
   const { clearOverlays } = useOverlayManager()
   const { clearOverlays } = useOverlayManager()
 
 

+ 2 - 3
packages/atlas/src/api/client/cache.ts

@@ -273,10 +273,9 @@ const cache = new InMemoryCache({
     StorageDataObject: {
     StorageDataObject: {
       fields: {
       fields: {
         resolvedUrls: {
         resolvedUrls: {
-          read: (resolvedUrl, { readField }) => {
+          read: (resolvedUrls, { readField }) => {
             const isAccepted = readField('isAccepted')
             const isAccepted = readField('isAccepted')
-
-            return isAccepted ? resolvedUrl : []
+            return isAccepted ? resolvedUrls : []
           },
           },
         },
         },
         size: {
         size: {

+ 0 - 74
packages/atlas/src/api/client/index.ts

@@ -3,17 +3,11 @@ import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
 import { getMainDefinition } from '@apollo/client/utilities'
 import { getMainDefinition } from '@apollo/client/utilities'
 import { createClient } from 'graphql-ws'
 import { createClient } from 'graphql-ws'
 
 
-import { atlasConfig } from '@/config'
 import { ORION_GRAPHQL_URL, QUERY_NODE_GRAPHQL_SUBSCRIPTION_URL } from '@/config/env'
 import { ORION_GRAPHQL_URL, QUERY_NODE_GRAPHQL_SUBSCRIPTION_URL } from '@/config/env'
-import { logDistributorPerformance, testAssetDownload } from '@/providers/assets/assets.helpers'
 import { useUserLocationStore } from '@/providers/userLocation'
 import { useUserLocationStore } from '@/providers/userLocation'
-import { AssetLogger, ConsoleLogger, DistributorEventEntry, SentryLogger } from '@/utils/logs'
-import { TimeoutError, withTimeout } from '@/utils/misc'
 
 
 import cache from './cache'
 import cache from './cache'
 
 
-import { StorageDataObject } from '../queries/__generated__/baseTypes.generated'
-
 const delayLink = new ApolloLink((operation, forward) => {
 const delayLink = new ApolloLink((operation, forward) => {
   const ctx = operation.getContext()
   const ctx = operation.getContext()
   if (!ctx.delay) {
   if (!ctx.delay) {
@@ -29,9 +23,6 @@ const delayLink = new ApolloLink((operation, forward) => {
   })
   })
 })
 })
 
 
-const MAX_ALLOWED_RETRIES = 10
-const bannedDistributorUrls: Record<string, number> = {}
-
 const createApolloClient = () => {
 const createApolloClient = () => {
   const subscriptionLink = new GraphQLWsLink(
   const subscriptionLink = new GraphQLWsLink(
     createClient({
     createClient({
@@ -71,71 +62,6 @@ const createApolloClient = () => {
   return new ApolloClient({
   return new ApolloClient({
     cache,
     cache,
     link: operationSplitLink,
     link: operationSplitLink,
-    resolvers: {
-      StorageDataObject: {
-        resolvedUrl: async (parent: StorageDataObject) => {
-          if (!parent.isAccepted) {
-            return null
-          }
-
-          // skip distributor url if he failed more than n times(where n is MAX_ALLOWED_RETRIES)
-          const resolvedUrls = parent.resolvedUrls?.filter((url) => {
-            const distributorUrl = url.split(`/${atlasConfig.storage.assetPath}/${parent.id}`)[0]
-            return (bannedDistributorUrls[distributorUrl] || 0) <= MAX_ALLOWED_RETRIES
-          })
-
-          for (const resolvedUrl of resolvedUrls) {
-            if (!parent.type) {
-              return null
-            }
-
-            if (parent.type.__typename === 'DataObjectTypeChannelPayoutsPayload') {
-              // if this is a payload file skip testing and just return first url.
-              return resolvedUrls[0]
-            }
-            const distributorUrl = resolvedUrl.split(`/${atlasConfig.storage.assetPath}/${parent.id}`)[0]
-
-            const assetTestPromise = testAssetDownload(resolvedUrl, parent.type)
-            const assetTestPromiseWithTimeout = withTimeout(assetTestPromise, atlasConfig.storage.assetResponseTimeout)
-            const eventEntry: DistributorEventEntry = {
-              distributorUrl,
-              dataObjectId: parent.id,
-              dataObjectType: parent.type?.__typename,
-            }
-
-            try {
-              await assetTestPromiseWithTimeout
-
-              logDistributorPerformance(resolvedUrl, eventEntry)
-              return resolvedUrl
-            } catch (err) {
-              if (err instanceof MediaError) {
-                SentryLogger.error('Error during asset download test, media is not supported', 'AssetsManager', err, {
-                  asset: { parent, resolvedUrl, mediaError: err },
-                })
-                return null
-              }
-              bannedDistributorUrls[distributorUrl] = (bannedDistributorUrls[distributorUrl] || 0) + 1
-              if (err instanceof TimeoutError) {
-                AssetLogger.logDistributorResponseTimeout(eventEntry)
-                ConsoleLogger.warn(
-                  `Distributor didn't respond in ${atlasConfig.storage.assetResponseTimeout} seconds`,
-                  {
-                    dataObject: parent,
-                  }
-                )
-              } else {
-                AssetLogger.logDistributorError(eventEntry)
-                SentryLogger.error('Error during asset download test', 'AssetsManager', err, {
-                  asset: { parent, resolvedUrl },
-                })
-              }
-            }
-          }
-          return null
-        },
-      },
-    },
   })
   })
 }
 }
 
 

+ 7 - 3
packages/atlas/src/api/hooks/channel.ts

@@ -23,6 +23,7 @@ import {
   useGetTop10ChannelsQuery,
   useGetTop10ChannelsQuery,
   useUnfollowChannelMutation,
   useUnfollowChannelMutation,
 } from '@/api/queries/__generated__/channels.generated'
 } from '@/api/queries/__generated__/channels.generated'
+import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics'
 
 
 export const useBasicChannel = (
 export const useBasicChannel = (
   id: string,
   id: string,
@@ -82,9 +83,11 @@ export const useBasicChannels = (
 
 
 export const useFollowChannel = (opts?: MutationHookOptions<FollowChannelMutation>) => {
 export const useFollowChannel = (opts?: MutationHookOptions<FollowChannelMutation>) => {
   const [followChannel, rest] = useFollowChannelMutation()
   const [followChannel, rest] = useFollowChannelMutation()
+  const { trackChannelFollow } = useSegmentAnalytics()
   return {
   return {
-    followChannel: (id: string) =>
-      followChannel({
+    followChannel: (id: string) => {
+      trackChannelFollow(id)
+      return followChannel({
         ...opts,
         ...opts,
         variables: {
         variables: {
           channelId: id,
           channelId: id,
@@ -100,7 +103,8 @@ export const useFollowChannel = (opts?: MutationHookOptions<FollowChannelMutatio
             },
             },
           })
           })
         },
         },
-      }),
+      })
+    },
     ...rest,
     ...rest,
   }
   }
 }
 }

+ 2 - 1
packages/atlas/src/api/queries/__generated__/baseTypes.generated.ts

@@ -3850,9 +3850,11 @@ export type MutationSetVideoViewPerIpTimeLimitArgs = {
 
 
 export type MutationSetVideoWeightsArgs = {
 export type MutationSetVideoWeightsArgs = {
   commentsWeight: Scalars['Float']
   commentsWeight: Scalars['Float']
+  joysteamTimestampSubWeight: Scalars['Float']
   newnessWeight: Scalars['Float']
   newnessWeight: Scalars['Float']
   reactionsWeight: Scalars['Float']
   reactionsWeight: Scalars['Float']
   viewsWeight: Scalars['Float']
   viewsWeight: Scalars['Float']
+  ytTimestampSubWeight: Scalars['Float']
 }
 }
 
 
 export type MutationSignAppActionCommitmentArgs = {
 export type MutationSignAppActionCommitmentArgs = {
@@ -6573,7 +6575,6 @@ export type StorageDataObject = {
   ipfsHash: Scalars['String']
   ipfsHash: Scalars['String']
   /** Whether the data object was uploaded and accepted by the storage provider */
   /** Whether the data object was uploaded and accepted by the storage provider */
   isAccepted: Scalars['Boolean']
   isAccepted: Scalars['Boolean']
-  resolvedUrl?: Maybe<Scalars['String']>
   /** Resolved asset urls */
   /** Resolved asset urls */
   resolvedUrls: Array<Scalars['String']>
   resolvedUrls: Array<Scalars['String']>
   /** Data object size in bytes */
   /** Data object size in bytes */

+ 0 - 1
packages/atlas/src/api/queries/__generated__/bids.generated.tsx

@@ -39,7 +39,6 @@ export type GetBidsQuery = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean

+ 0 - 15
packages/atlas/src/api/queries/__generated__/channels.generated.tsx

@@ -46,7 +46,6 @@ export type GetFullChannelQuery = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -70,7 +69,6 @@ export type GetFullChannelQuery = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -89,7 +87,6 @@ export type GetFullChannelQuery = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -131,7 +128,6 @@ export type GetExtendedBasicChannelsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -189,7 +185,6 @@ export type GetExtendedFullChannelsQuery = {
                   __typename?: 'StorageDataObject'
                   __typename?: 'StorageDataObject'
                   id: string
                   id: string
                   resolvedUrls: Array<string>
                   resolvedUrls: Array<string>
-                  resolvedUrl?: string | null
                   createdAt: Date
                   createdAt: Date
                   size: string
                   size: string
                   isAccepted: boolean
                   isAccepted: boolean
@@ -213,7 +208,6 @@ export type GetExtendedFullChannelsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -232,7 +226,6 @@ export type GetExtendedFullChannelsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -279,7 +272,6 @@ export type GetBasicChannelsConnectionQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -340,7 +332,6 @@ export type GetTop10ChannelsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -380,7 +371,6 @@ export type GetDiscoverChannelsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -423,7 +413,6 @@ export type GetChannelNftCollectorsQuery = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -493,7 +482,6 @@ export type GetPayloadDataByCommitmentQuery = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -647,7 +635,6 @@ export type GetTopSellingChannelsFromThreePeriodsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -681,7 +668,6 @@ export type GetTopSellingChannelsFromThreePeriodsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -715,7 +701,6 @@ export type GetTopSellingChannelsFromThreePeriodsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean

+ 0 - 4
packages/atlas/src/api/queries/__generated__/comments.generated.tsx

@@ -34,7 +34,6 @@ export type GetCommentQuery = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -101,7 +100,6 @@ export type GetCommentRepliesConnectionQuery = {
                     __typename?: 'StorageDataObject'
                     __typename?: 'StorageDataObject'
                     id: string
                     id: string
                     resolvedUrls: Array<string>
                     resolvedUrls: Array<string>
-                    resolvedUrl?: string | null
                     createdAt: Date
                     createdAt: Date
                     size: string
                     size: string
                     isAccepted: boolean
                     isAccepted: boolean
@@ -166,7 +164,6 @@ export type GetUserCommentsAndVideoCommentsConnectionQuery = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -222,7 +219,6 @@ export type GetUserCommentsAndVideoCommentsConnectionQuery = {
                     __typename?: 'StorageDataObject'
                     __typename?: 'StorageDataObject'
                     id: string
                     id: string
                     resolvedUrls: Array<string>
                     resolvedUrls: Array<string>
-                    resolvedUrl?: string | null
                     createdAt: Date
                     createdAt: Date
                     size: string
                     size: string
                     isAccepted: boolean
                     isAccepted: boolean

+ 0 - 12
packages/atlas/src/api/queries/__generated__/featured.generated.tsx

@@ -36,7 +36,6 @@ export type GetVideoHeroQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -56,7 +55,6 @@ export type GetVideoHeroQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -104,7 +102,6 @@ export type GetVideoHeroQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -128,7 +125,6 @@ export type GetVideoHeroQuery = {
                   __typename?: 'StorageDataObject'
                   __typename?: 'StorageDataObject'
                   id: string
                   id: string
                   resolvedUrls: Array<string>
                   resolvedUrls: Array<string>
-                  resolvedUrl?: string | null
                   createdAt: Date
                   createdAt: Date
                   size: string
                   size: string
                   isAccepted: boolean
                   isAccepted: boolean
@@ -161,7 +157,6 @@ export type GetVideoHeroQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -223,7 +218,6 @@ export type GetVideoHeroQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -265,7 +259,6 @@ export type GetVideoHeroQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -302,7 +295,6 @@ export type GetVideoHeroQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -367,7 +359,6 @@ export type GetAllCategoriesFeaturedVideosQuery = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -387,7 +378,6 @@ export type GetAllCategoriesFeaturedVideosQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -468,7 +458,6 @@ export type GetCategoryFeaturedVideosQuery = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -488,7 +477,6 @@ export type GetCategoryFeaturedVideosQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean

+ 0 - 69
packages/atlas/src/api/queries/__generated__/fragments.generated.tsx

@@ -21,7 +21,6 @@ export type BasicChannelFieldsFragment = {
     __typename?: 'StorageDataObject'
     __typename?: 'StorageDataObject'
     id: string
     id: string
     resolvedUrls: Array<string>
     resolvedUrls: Array<string>
-    resolvedUrl?: string | null
     createdAt: Date
     createdAt: Date
     size: string
     size: string
     isAccepted: boolean
     isAccepted: boolean
@@ -66,7 +65,6 @@ export type FullChannelFieldsFragment = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -90,7 +88,6 @@ export type FullChannelFieldsFragment = {
     __typename?: 'StorageDataObject'
     __typename?: 'StorageDataObject'
     id: string
     id: string
     resolvedUrls: Array<string>
     resolvedUrls: Array<string>
-    resolvedUrl?: string | null
     createdAt: Date
     createdAt: Date
     size: string
     size: string
     isAccepted: boolean
     isAccepted: boolean
@@ -109,7 +106,6 @@ export type FullChannelFieldsFragment = {
     __typename?: 'StorageDataObject'
     __typename?: 'StorageDataObject'
     id: string
     id: string
     resolvedUrls: Array<string>
     resolvedUrls: Array<string>
-    resolvedUrl?: string | null
     createdAt: Date
     createdAt: Date
     size: string
     size: string
     isAccepted: boolean
     isAccepted: boolean
@@ -157,7 +153,6 @@ export type ExtendedFullChannelFieldsFragment = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -181,7 +176,6 @@ export type ExtendedFullChannelFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -200,7 +194,6 @@ export type ExtendedFullChannelFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -234,7 +227,6 @@ export type ExtendedBasicChannelFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -266,7 +258,6 @@ export type BasicMembershipFieldsFragment = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -308,7 +299,6 @@ export type FullMembershipFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -327,7 +317,6 @@ export type FullMembershipFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -353,7 +342,6 @@ export type FullMembershipFieldsFragment = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -378,7 +366,6 @@ export type StorageDataObjectFieldsFragment = {
   __typename?: 'StorageDataObject'
   __typename?: 'StorageDataObject'
   id: string
   id: string
   resolvedUrls: Array<string>
   resolvedUrls: Array<string>
-  resolvedUrl?: string | null
   createdAt: Date
   createdAt: Date
   size: string
   size: string
   isAccepted: boolean
   isAccepted: boolean
@@ -433,7 +420,6 @@ export type SubtitlesFieldsFragment = {
     __typename?: 'StorageDataObject'
     __typename?: 'StorageDataObject'
     id: string
     id: string
     resolvedUrls: Array<string>
     resolvedUrls: Array<string>
-    resolvedUrl?: string | null
     createdAt: Date
     createdAt: Date
     size: string
     size: string
     isAccepted: boolean
     isAccepted: boolean
@@ -472,7 +458,6 @@ export type BasicVideoFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -492,7 +477,6 @@ export type BasicVideoFieldsFragment = {
     __typename?: 'StorageDataObject'
     __typename?: 'StorageDataObject'
     id: string
     id: string
     resolvedUrls: Array<string>
     resolvedUrls: Array<string>
-    resolvedUrl?: string | null
     createdAt: Date
     createdAt: Date
     size: string
     size: string
     isAccepted: boolean
     isAccepted: boolean
@@ -540,7 +524,6 @@ export type BasicVideoFieldsFragment = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -564,7 +547,6 @@ export type BasicVideoFieldsFragment = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -597,7 +579,6 @@ export type BasicVideoFieldsFragment = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -659,7 +640,6 @@ export type BasicVideoFieldsFragment = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -701,7 +681,6 @@ export type BasicVideoFieldsFragment = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -738,7 +717,6 @@ export type BasicVideoFieldsFragment = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -804,7 +782,6 @@ export type FullVideoFieldsFragment = {
     __typename?: 'StorageDataObject'
     __typename?: 'StorageDataObject'
     id: string
     id: string
     resolvedUrls: Array<string>
     resolvedUrls: Array<string>
-    resolvedUrl?: string | null
     createdAt: Date
     createdAt: Date
     size: string
     size: string
     isAccepted: boolean
     isAccepted: boolean
@@ -823,7 +800,6 @@ export type FullVideoFieldsFragment = {
     __typename?: 'StorageDataObject'
     __typename?: 'StorageDataObject'
     id: string
     id: string
     resolvedUrls: Array<string>
     resolvedUrls: Array<string>
-    resolvedUrl?: string | null
     createdAt: Date
     createdAt: Date
     size: string
     size: string
     isAccepted: boolean
     isAccepted: boolean
@@ -866,7 +842,6 @@ export type FullVideoFieldsFragment = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -890,7 +865,6 @@ export type FullVideoFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -909,7 +883,6 @@ export type FullVideoFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -965,7 +938,6 @@ export type FullVideoFieldsFragment = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -989,7 +961,6 @@ export type FullVideoFieldsFragment = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -1022,7 +993,6 @@ export type FullVideoFieldsFragment = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -1084,7 +1054,6 @@ export type FullVideoFieldsFragment = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1126,7 +1095,6 @@ export type FullVideoFieldsFragment = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1163,7 +1131,6 @@ export type FullVideoFieldsFragment = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1201,7 +1168,6 @@ export type FullVideoFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -1252,7 +1218,6 @@ export type BasicNftFieldsFragment = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -1276,7 +1241,6 @@ export type BasicNftFieldsFragment = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -1309,7 +1273,6 @@ export type BasicNftFieldsFragment = {
                     __typename?: 'StorageDataObject'
                     __typename?: 'StorageDataObject'
                     id: string
                     id: string
                     resolvedUrls: Array<string>
                     resolvedUrls: Array<string>
-                    resolvedUrl?: string | null
                     createdAt: Date
                     createdAt: Date
                     size: string
                     size: string
                     isAccepted: boolean
                     isAccepted: boolean
@@ -1371,7 +1334,6 @@ export type BasicNftFieldsFragment = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -1413,7 +1375,6 @@ export type BasicNftFieldsFragment = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -1450,7 +1411,6 @@ export type BasicNftFieldsFragment = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -1508,7 +1468,6 @@ export type FullNftFieldsFragment = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -1528,7 +1487,6 @@ export type FullNftFieldsFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -1576,7 +1534,6 @@ export type FullNftFieldsFragment = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1600,7 +1557,6 @@ export type FullNftFieldsFragment = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -1633,7 +1589,6 @@ export type FullNftFieldsFragment = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -1695,7 +1650,6 @@ export type FullNftFieldsFragment = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1737,7 +1691,6 @@ export type FullNftFieldsFragment = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1774,7 +1727,6 @@ export type FullNftFieldsFragment = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1829,7 +1781,6 @@ export type FullNftFieldsFragment = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -1853,7 +1804,6 @@ export type FullNftFieldsFragment = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -1886,7 +1836,6 @@ export type FullNftFieldsFragment = {
                     __typename?: 'StorageDataObject'
                     __typename?: 'StorageDataObject'
                     id: string
                     id: string
                     resolvedUrls: Array<string>
                     resolvedUrls: Array<string>
-                    resolvedUrl?: string | null
                     createdAt: Date
                     createdAt: Date
                     size: string
                     size: string
                     isAccepted: boolean
                     isAccepted: boolean
@@ -1948,7 +1897,6 @@ export type FullNftFieldsFragment = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -1990,7 +1938,6 @@ export type FullNftFieldsFragment = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -2027,7 +1974,6 @@ export type FullNftFieldsFragment = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -2077,7 +2023,6 @@ export type BasicBidFieldsFragment = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -2127,7 +2072,6 @@ export type FullBidFieldsFragment = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -2178,7 +2122,6 @@ export type CommentFieldsFragment = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -2235,7 +2178,6 @@ export type MetaprotocolTransactionResultFields_MetaprotocolTransactionResultCom
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -2289,7 +2231,6 @@ export type MetaprotocolTransactionResultFields_MetaprotocolTransactionResultCom
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -2343,7 +2284,6 @@ export type MetaprotocolTransactionResultFields_MetaprotocolTransactionResultCom
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -2397,7 +2337,6 @@ export type MetaprotocolTransactionResultFields_MetaprotocolTransactionResultCom
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -2462,7 +2401,6 @@ export type BasicNftOwnerFields_NftOwnerChannel_Fragment = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -2501,7 +2439,6 @@ export type BasicNftOwnerFields_NftOwnerMember_Fragment = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -2549,7 +2486,6 @@ export type BasicFeaturedVideoFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -2569,7 +2505,6 @@ export type BasicFeaturedVideoFragment = {
     __typename?: 'StorageDataObject'
     __typename?: 'StorageDataObject'
     id: string
     id: string
     resolvedUrls: Array<string>
     resolvedUrls: Array<string>
-    resolvedUrl?: string | null
     createdAt: Date
     createdAt: Date
     size: string
     size: string
     isAccepted: boolean
     isAccepted: boolean
@@ -2639,7 +2574,6 @@ export type BasicVideoFeaturedInCategoryFragment = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -2659,7 +2593,6 @@ export type BasicVideoFeaturedInCategoryFragment = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -2713,7 +2646,6 @@ export type BasicVideoActivityFieldsFragment = {
     __typename?: 'StorageDataObject'
     __typename?: 'StorageDataObject'
     id: string
     id: string
     resolvedUrls: Array<string>
     resolvedUrls: Array<string>
-    resolvedUrl?: string | null
     createdAt: Date
     createdAt: Date
     size: string
     size: string
     isAccepted: boolean
     isAccepted: boolean
@@ -2743,7 +2675,6 @@ export const StorageDataObjectFieldsFragmentDoc = gql`
   fragment StorageDataObjectFields on StorageDataObject {
   fragment StorageDataObjectFields on StorageDataObject {
     id
     id
     resolvedUrls
     resolvedUrls
-    resolvedUrl @client
     createdAt
     createdAt
     size
     size
     isAccepted
     isAccepted

+ 0 - 3
packages/atlas/src/api/queries/__generated__/memberships.generated.tsx

@@ -32,7 +32,6 @@ export type GetMembershipsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -51,7 +50,6 @@ export type GetMembershipsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -77,7 +75,6 @@ export type GetMembershipsQuery = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean

+ 0 - 57
packages/atlas/src/api/queries/__generated__/nfts.generated.tsx

@@ -44,7 +44,6 @@ export type GetNftQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -64,7 +63,6 @@ export type GetNftQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -112,7 +110,6 @@ export type GetNftQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -136,7 +133,6 @@ export type GetNftQuery = {
                   __typename?: 'StorageDataObject'
                   __typename?: 'StorageDataObject'
                   id: string
                   id: string
                   resolvedUrls: Array<string>
                   resolvedUrls: Array<string>
-                  resolvedUrl?: string | null
                   createdAt: Date
                   createdAt: Date
                   size: string
                   size: string
                   isAccepted: boolean
                   isAccepted: boolean
@@ -169,7 +165,6 @@ export type GetNftQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -231,7 +226,6 @@ export type GetNftQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -273,7 +267,6 @@ export type GetNftQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -310,7 +303,6 @@ export type GetNftQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -365,7 +357,6 @@ export type GetNftQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -389,7 +380,6 @@ export type GetNftQuery = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -422,7 +412,6 @@ export type GetNftQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -484,7 +473,6 @@ export type GetNftQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -526,7 +514,6 @@ export type GetNftQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -563,7 +550,6 @@ export type GetNftQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -631,7 +617,6 @@ export type GetNftsQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -651,7 +636,6 @@ export type GetNftsQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -699,7 +683,6 @@ export type GetNftsQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -723,7 +706,6 @@ export type GetNftsQuery = {
                   __typename?: 'StorageDataObject'
                   __typename?: 'StorageDataObject'
                   id: string
                   id: string
                   resolvedUrls: Array<string>
                   resolvedUrls: Array<string>
-                  resolvedUrl?: string | null
                   createdAt: Date
                   createdAt: Date
                   size: string
                   size: string
                   isAccepted: boolean
                   isAccepted: boolean
@@ -756,7 +738,6 @@ export type GetNftsQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -818,7 +799,6 @@ export type GetNftsQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -860,7 +840,6 @@ export type GetNftsQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -897,7 +876,6 @@ export type GetNftsQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -952,7 +930,6 @@ export type GetNftsQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -976,7 +953,6 @@ export type GetNftsQuery = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -1009,7 +985,6 @@ export type GetNftsQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -1071,7 +1046,6 @@ export type GetNftsQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1113,7 +1087,6 @@ export type GetNftsQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1150,7 +1123,6 @@ export type GetNftsQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1224,7 +1196,6 @@ export type GetNftsConnectionQuery = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -1244,7 +1215,6 @@ export type GetNftsConnectionQuery = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -1292,7 +1262,6 @@ export type GetNftsConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1316,7 +1285,6 @@ export type GetNftsConnectionQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -1349,7 +1317,6 @@ export type GetNftsConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1411,7 +1378,6 @@ export type GetNftsConnectionQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -1453,7 +1419,6 @@ export type GetNftsConnectionQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -1490,7 +1455,6 @@ export type GetNftsConnectionQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -1545,7 +1509,6 @@ export type GetNftsConnectionQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1569,7 +1532,6 @@ export type GetNftsConnectionQuery = {
                   __typename?: 'StorageDataObject'
                   __typename?: 'StorageDataObject'
                   id: string
                   id: string
                   resolvedUrls: Array<string>
                   resolvedUrls: Array<string>
-                  resolvedUrl?: string | null
                   createdAt: Date
                   createdAt: Date
                   size: string
                   size: string
                   isAccepted: boolean
                   isAccepted: boolean
@@ -1602,7 +1564,6 @@ export type GetNftsConnectionQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1664,7 +1625,6 @@ export type GetNftsConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1706,7 +1666,6 @@ export type GetNftsConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1743,7 +1702,6 @@ export type GetNftsConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1804,7 +1762,6 @@ export type GetFeaturedNftsVideosQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -1832,7 +1789,6 @@ export type GetFeaturedNftsVideosQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -1852,7 +1808,6 @@ export type GetFeaturedNftsVideosQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -1900,7 +1855,6 @@ export type GetFeaturedNftsVideosQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1924,7 +1878,6 @@ export type GetFeaturedNftsVideosQuery = {
                   __typename?: 'StorageDataObject'
                   __typename?: 'StorageDataObject'
                   id: string
                   id: string
                   resolvedUrls: Array<string>
                   resolvedUrls: Array<string>
-                  resolvedUrl?: string | null
                   createdAt: Date
                   createdAt: Date
                   size: string
                   size: string
                   isAccepted: boolean
                   isAccepted: boolean
@@ -1957,7 +1910,6 @@ export type GetFeaturedNftsVideosQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -2019,7 +1971,6 @@ export type GetFeaturedNftsVideosQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -2061,7 +2012,6 @@ export type GetFeaturedNftsVideosQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -2098,7 +2048,6 @@ export type GetFeaturedNftsVideosQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -2153,7 +2102,6 @@ export type GetFeaturedNftsVideosQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -2177,7 +2125,6 @@ export type GetFeaturedNftsVideosQuery = {
               __typename?: 'StorageDataObject'
               __typename?: 'StorageDataObject'
               id: string
               id: string
               resolvedUrls: Array<string>
               resolvedUrls: Array<string>
-              resolvedUrl?: string | null
               createdAt: Date
               createdAt: Date
               size: string
               size: string
               isAccepted: boolean
               isAccepted: boolean
@@ -2210,7 +2157,6 @@ export type GetFeaturedNftsVideosQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -2272,7 +2218,6 @@ export type GetFeaturedNftsVideosQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -2314,7 +2259,6 @@ export type GetFeaturedNftsVideosQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -2351,7 +2295,6 @@ export type GetFeaturedNftsVideosQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean

+ 0 - 90
packages/atlas/src/api/queries/__generated__/notifications.generated.tsx

@@ -52,7 +52,6 @@ export type GetNotificationsConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -88,7 +87,6 @@ export type GetNotificationsConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -119,7 +117,6 @@ export type GetNotificationsConnectionQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -156,7 +153,6 @@ export type GetNotificationsConnectionQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -194,7 +190,6 @@ export type GetNotificationsConnectionQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -236,7 +231,6 @@ export type GetNotificationsConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -266,7 +260,6 @@ export type GetNotificationsConnectionQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -303,7 +296,6 @@ export type GetNotificationsConnectionQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -341,7 +333,6 @@ export type GetNotificationsConnectionQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -391,7 +382,6 @@ export type GetNotificationsConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -432,7 +422,6 @@ export type GetNotificationsConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -462,7 +451,6 @@ export type GetNotificationsConnectionQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -499,7 +487,6 @@ export type GetNotificationsConnectionQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -537,7 +524,6 @@ export type GetNotificationsConnectionQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -579,7 +565,6 @@ export type GetNotificationsConnectionQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -609,7 +594,6 @@ export type GetNotificationsConnectionQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -648,7 +632,6 @@ export type GetNotificationsConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -678,7 +661,6 @@ export type GetNotificationsConnectionQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -715,7 +697,6 @@ export type GetNotificationsConnectionQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -753,7 +734,6 @@ export type GetNotificationsConnectionQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -811,7 +791,6 @@ export type GetNftHistoryQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -851,7 +830,6 @@ export type GetNftHistoryQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -894,7 +872,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -932,7 +909,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -975,7 +951,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1013,7 +988,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1051,7 +1025,6 @@ export type GetNftHistoryQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1094,7 +1067,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1132,7 +1104,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1176,7 +1147,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1214,7 +1184,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1264,7 +1233,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1302,7 +1270,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1339,7 +1306,6 @@ export type GetNftHistoryQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1382,7 +1348,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1420,7 +1385,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1461,7 +1425,6 @@ export type GetNftHistoryQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -1503,7 +1466,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1541,7 +1503,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1585,7 +1546,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1623,7 +1583,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1666,7 +1625,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1704,7 +1662,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1742,7 +1699,6 @@ export type GetNftHistoryQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1785,7 +1741,6 @@ export type GetNftHistoryQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1823,7 +1778,6 @@ export type GetNftHistoryQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1901,7 +1855,6 @@ export type GetNftActivitiesQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1933,7 +1886,6 @@ export type GetNftActivitiesQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -1973,7 +1925,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -2011,7 +1962,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -2049,7 +1999,6 @@ export type GetNftActivitiesQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -2085,7 +2034,6 @@ export type GetNftActivitiesQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -2116,7 +2064,6 @@ export type GetNftActivitiesQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -2149,7 +2096,6 @@ export type GetNftActivitiesQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -2186,7 +2132,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -2224,7 +2169,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -2267,7 +2211,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -2305,7 +2248,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -2343,7 +2285,6 @@ export type GetNftActivitiesQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -2373,7 +2314,6 @@ export type GetNftActivitiesQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -2404,7 +2344,6 @@ export type GetNftActivitiesQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -2440,7 +2379,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -2478,7 +2416,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -2513,7 +2450,6 @@ export type GetNftActivitiesQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -2549,7 +2485,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -2587,7 +2522,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -2637,7 +2571,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -2675,7 +2608,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -2713,7 +2645,6 @@ export type GetNftActivitiesQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -2743,7 +2674,6 @@ export type GetNftActivitiesQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -2776,7 +2706,6 @@ export type GetNftActivitiesQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -2813,7 +2742,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -2851,7 +2779,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -2892,7 +2819,6 @@ export type GetNftActivitiesQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -2931,7 +2857,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -2969,7 +2894,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -3000,7 +2924,6 @@ export type GetNftActivitiesQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -3030,7 +2953,6 @@ export type GetNftActivitiesQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -3066,7 +2988,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -3104,7 +3025,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -3139,7 +3059,6 @@ export type GetNftActivitiesQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -3175,7 +3094,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -3213,7 +3131,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -3254,7 +3171,6 @@ export type GetNftActivitiesQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -3284,7 +3200,6 @@ export type GetNftActivitiesQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -3321,7 +3236,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -3359,7 +3273,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean
@@ -3395,7 +3308,6 @@ export type GetNftActivitiesQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -3432,7 +3344,6 @@ export type GetNftActivitiesQuery = {
                                     __typename?: 'StorageDataObject'
                                     __typename?: 'StorageDataObject'
                                     id: string
                                     id: string
                                     resolvedUrls: Array<string>
                                     resolvedUrls: Array<string>
-                                    resolvedUrl?: string | null
                                     createdAt: Date
                                     createdAt: Date
                                     size: string
                                     size: string
                                     isAccepted: boolean
                                     isAccepted: boolean
@@ -3470,7 +3381,6 @@ export type GetNftActivitiesQuery = {
                                   __typename?: 'StorageDataObject'
                                   __typename?: 'StorageDataObject'
                                   id: string
                                   id: string
                                   resolvedUrls: Array<string>
                                   resolvedUrls: Array<string>
-                                  resolvedUrl?: string | null
                                   createdAt: Date
                                   createdAt: Date
                                   size: string
                                   size: string
                                   isAccepted: boolean
                                   isAccepted: boolean

+ 0 - 4
packages/atlas/src/api/queries/__generated__/transactionEvents.generated.tsx

@@ -61,7 +61,6 @@ export type GetMetaprotocolTransactionStatusEventsQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -114,7 +113,6 @@ export type GetMetaprotocolTransactionStatusEventsQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -167,7 +165,6 @@ export type GetMetaprotocolTransactionStatusEventsQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -220,7 +217,6 @@ export type GetMetaprotocolTransactionStatusEventsQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean

+ 0 - 60
packages/atlas/src/api/queries/__generated__/videos.generated.tsx

@@ -47,7 +47,6 @@ export type GetFullVideoQuery = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -66,7 +65,6 @@ export type GetFullVideoQuery = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -109,7 +107,6 @@ export type GetFullVideoQuery = {
                   __typename?: 'StorageDataObject'
                   __typename?: 'StorageDataObject'
                   id: string
                   id: string
                   resolvedUrls: Array<string>
                   resolvedUrls: Array<string>
-                  resolvedUrl?: string | null
                   createdAt: Date
                   createdAt: Date
                   size: string
                   size: string
                   isAccepted: boolean
                   isAccepted: boolean
@@ -133,7 +130,6 @@ export type GetFullVideoQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -152,7 +148,6 @@ export type GetFullVideoQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -208,7 +203,6 @@ export type GetFullVideoQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -232,7 +226,6 @@ export type GetFullVideoQuery = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -265,7 +258,6 @@ export type GetFullVideoQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -327,7 +319,6 @@ export type GetFullVideoQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -369,7 +360,6 @@ export type GetFullVideoQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -406,7 +396,6 @@ export type GetFullVideoQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -444,7 +433,6 @@ export type GetFullVideoQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -500,7 +488,6 @@ export type GetBasicVideosConnectionQuery = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -520,7 +507,6 @@ export type GetBasicVideosConnectionQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -568,7 +554,6 @@ export type GetBasicVideosConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -592,7 +577,6 @@ export type GetBasicVideosConnectionQuery = {
                     __typename?: 'StorageDataObject'
                     __typename?: 'StorageDataObject'
                     id: string
                     id: string
                     resolvedUrls: Array<string>
                     resolvedUrls: Array<string>
-                    resolvedUrl?: string | null
                     createdAt: Date
                     createdAt: Date
                     size: string
                     size: string
                     isAccepted: boolean
                     isAccepted: boolean
@@ -625,7 +609,6 @@ export type GetBasicVideosConnectionQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -687,7 +670,6 @@ export type GetBasicVideosConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -729,7 +711,6 @@ export type GetBasicVideosConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -766,7 +747,6 @@ export type GetBasicVideosConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -851,7 +831,6 @@ export type GetFullVideosConnectionQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -870,7 +849,6 @@ export type GetFullVideosConnectionQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -913,7 +891,6 @@ export type GetFullVideosConnectionQuery = {
                       __typename?: 'StorageDataObject'
                       __typename?: 'StorageDataObject'
                       id: string
                       id: string
                       resolvedUrls: Array<string>
                       resolvedUrls: Array<string>
-                      resolvedUrl?: string | null
                       createdAt: Date
                       createdAt: Date
                       size: string
                       size: string
                       isAccepted: boolean
                       isAccepted: boolean
@@ -937,7 +914,6 @@ export type GetFullVideosConnectionQuery = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -956,7 +932,6 @@ export type GetFullVideosConnectionQuery = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -1012,7 +987,6 @@ export type GetFullVideosConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -1036,7 +1010,6 @@ export type GetFullVideosConnectionQuery = {
                     __typename?: 'StorageDataObject'
                     __typename?: 'StorageDataObject'
                     id: string
                     id: string
                     resolvedUrls: Array<string>
                     resolvedUrls: Array<string>
-                    resolvedUrl?: string | null
                     createdAt: Date
                     createdAt: Date
                     size: string
                     size: string
                     isAccepted: boolean
                     isAccepted: boolean
@@ -1069,7 +1042,6 @@ export type GetFullVideosConnectionQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1131,7 +1103,6 @@ export type GetFullVideosConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1173,7 +1144,6 @@ export type GetFullVideosConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1210,7 +1180,6 @@ export type GetFullVideosConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -1248,7 +1217,6 @@ export type GetFullVideosConnectionQuery = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -1301,7 +1269,6 @@ export type GetBasicVideosQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -1321,7 +1288,6 @@ export type GetBasicVideosQuery = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -1369,7 +1335,6 @@ export type GetBasicVideosQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1393,7 +1358,6 @@ export type GetBasicVideosQuery = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -1426,7 +1390,6 @@ export type GetBasicVideosQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -1488,7 +1451,6 @@ export type GetBasicVideosQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1530,7 +1492,6 @@ export type GetBasicVideosQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1567,7 +1528,6 @@ export type GetBasicVideosQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1643,7 +1603,6 @@ export type GetFullVideosQuery = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -1662,7 +1621,6 @@ export type GetFullVideosQuery = {
       __typename?: 'StorageDataObject'
       __typename?: 'StorageDataObject'
       id: string
       id: string
       resolvedUrls: Array<string>
       resolvedUrls: Array<string>
-      resolvedUrl?: string | null
       createdAt: Date
       createdAt: Date
       size: string
       size: string
       isAccepted: boolean
       isAccepted: boolean
@@ -1705,7 +1663,6 @@ export type GetFullVideosQuery = {
                   __typename?: 'StorageDataObject'
                   __typename?: 'StorageDataObject'
                   id: string
                   id: string
                   resolvedUrls: Array<string>
                   resolvedUrls: Array<string>
-                  resolvedUrl?: string | null
                   createdAt: Date
                   createdAt: Date
                   size: string
                   size: string
                   isAccepted: boolean
                   isAccepted: boolean
@@ -1729,7 +1686,6 @@ export type GetFullVideosQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -1748,7 +1704,6 @@ export type GetFullVideosQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -1804,7 +1759,6 @@ export type GetFullVideosQuery = {
                           __typename?: 'StorageDataObject'
                           __typename?: 'StorageDataObject'
                           id: string
                           id: string
                           resolvedUrls: Array<string>
                           resolvedUrls: Array<string>
-                          resolvedUrl?: string | null
                           createdAt: Date
                           createdAt: Date
                           size: string
                           size: string
                           isAccepted: boolean
                           isAccepted: boolean
@@ -1828,7 +1782,6 @@ export type GetFullVideosQuery = {
                 __typename?: 'StorageDataObject'
                 __typename?: 'StorageDataObject'
                 id: string
                 id: string
                 resolvedUrls: Array<string>
                 resolvedUrls: Array<string>
-                resolvedUrl?: string | null
                 createdAt: Date
                 createdAt: Date
                 size: string
                 size: string
                 isAccepted: boolean
                 isAccepted: boolean
@@ -1861,7 +1814,6 @@ export type GetFullVideosQuery = {
                         __typename?: 'StorageDataObject'
                         __typename?: 'StorageDataObject'
                         id: string
                         id: string
                         resolvedUrls: Array<string>
                         resolvedUrls: Array<string>
-                        resolvedUrl?: string | null
                         createdAt: Date
                         createdAt: Date
                         size: string
                         size: string
                         isAccepted: boolean
                         isAccepted: boolean
@@ -1923,7 +1875,6 @@ export type GetFullVideosQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -1965,7 +1916,6 @@ export type GetFullVideosQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -2002,7 +1952,6 @@ export type GetFullVideosQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -2040,7 +1989,6 @@ export type GetFullVideosQuery = {
         __typename?: 'StorageDataObject'
         __typename?: 'StorageDataObject'
         id: string
         id: string
         resolvedUrls: Array<string>
         resolvedUrls: Array<string>
-        resolvedUrl?: string | null
         createdAt: Date
         createdAt: Date
         size: string
         size: string
         isAccepted: boolean
         isAccepted: boolean
@@ -2098,7 +2046,6 @@ export type GetMostViewedVideosConnectionQuery = {
             __typename?: 'StorageDataObject'
             __typename?: 'StorageDataObject'
             id: string
             id: string
             resolvedUrls: Array<string>
             resolvedUrls: Array<string>
-            resolvedUrl?: string | null
             createdAt: Date
             createdAt: Date
             size: string
             size: string
             isAccepted: boolean
             isAccepted: boolean
@@ -2118,7 +2065,6 @@ export type GetMostViewedVideosConnectionQuery = {
           __typename?: 'StorageDataObject'
           __typename?: 'StorageDataObject'
           id: string
           id: string
           resolvedUrls: Array<string>
           resolvedUrls: Array<string>
-          resolvedUrl?: string | null
           createdAt: Date
           createdAt: Date
           size: string
           size: string
           isAccepted: boolean
           isAccepted: boolean
@@ -2166,7 +2112,6 @@ export type GetMostViewedVideosConnectionQuery = {
                               __typename?: 'StorageDataObject'
                               __typename?: 'StorageDataObject'
                               id: string
                               id: string
                               resolvedUrls: Array<string>
                               resolvedUrls: Array<string>
-                              resolvedUrl?: string | null
                               createdAt: Date
                               createdAt: Date
                               size: string
                               size: string
                               isAccepted: boolean
                               isAccepted: boolean
@@ -2190,7 +2135,6 @@ export type GetMostViewedVideosConnectionQuery = {
                     __typename?: 'StorageDataObject'
                     __typename?: 'StorageDataObject'
                     id: string
                     id: string
                     resolvedUrls: Array<string>
                     resolvedUrls: Array<string>
-                    resolvedUrl?: string | null
                     createdAt: Date
                     createdAt: Date
                     size: string
                     size: string
                     isAccepted: boolean
                     isAccepted: boolean
@@ -2223,7 +2167,6 @@ export type GetMostViewedVideosConnectionQuery = {
                             __typename?: 'StorageDataObject'
                             __typename?: 'StorageDataObject'
                             id: string
                             id: string
                             resolvedUrls: Array<string>
                             resolvedUrls: Array<string>
-                            resolvedUrl?: string | null
                             createdAt: Date
                             createdAt: Date
                             size: string
                             size: string
                             isAccepted: boolean
                             isAccepted: boolean
@@ -2285,7 +2228,6 @@ export type GetMostViewedVideosConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -2327,7 +2269,6 @@ export type GetMostViewedVideosConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean
@@ -2364,7 +2305,6 @@ export type GetMostViewedVideosConnectionQuery = {
                                 __typename?: 'StorageDataObject'
                                 __typename?: 'StorageDataObject'
                                 id: string
                                 id: string
                                 resolvedUrls: Array<string>
                                 resolvedUrls: Array<string>
-                                resolvedUrl?: string | null
                                 createdAt: Date
                                 createdAt: Date
                                 size: string
                                 size: string
                                 isAccepted: boolean
                                 isAccepted: boolean

+ 0 - 1
packages/atlas/src/api/queries/fragments.graphql

@@ -91,7 +91,6 @@ fragment FullMembershipFields on Membership {
 fragment StorageDataObjectFields on StorageDataObject {
 fragment StorageDataObjectFields on StorageDataObject {
   id
   id
   resolvedUrls
   resolvedUrls
-  resolvedUrl @client
   createdAt
   createdAt
   size
   size
   isAccepted
   isAccepted

+ 1 - 1
packages/atlas/src/components/ActionBar/ActionBar.tsx

@@ -65,7 +65,7 @@ export const ActionBar = forwardRef<HTMLDivElement, ActionBarProps>(
     )
     )
 
 
     return (
     return (
-      <ActionBarContainer ref={ref} className={className} isActive={isActive}>
+      <ActionBarContainer ref={ref} className={`${className} action-bar`} isActive={isActive}>
         {fee && !isNoneCrypto && (
         {fee && !isNoneCrypto && (
           <FeeContainer>
           <FeeContainer>
             <Fee variant={smMatch ? 'h400' : 'h200'} withToken amount={fee || new BN(0)} loading={feeLoading} />
             <Fee variant={smMatch ? 'h400' : 'h200'} withToken amount={fee || new BN(0)} loading={feeLoading} />

+ 36 - 0
packages/atlas/src/components/AssetImage/AssetImage.tsx

@@ -0,0 +1,36 @@
+import { FC, ImgHTMLAttributes, ReactNode } from 'react'
+import { CSSTransition, SwitchTransition } from 'react-transition-group'
+
+import { SkeletonLoader } from '@/components/_loaders/SkeletonLoader'
+import { useGetAssetUrl } from '@/hooks/useGetAssetUrl'
+import { cVar, transitions } from '@/styles'
+
+export type AssetImageProps = {
+  isLoading?: boolean
+  resolvedUrls: string[] | undefined | null
+  imagePlaceholder?: ReactNode
+} & Omit<ImgHTMLAttributes<HTMLImageElement>, 'src'>
+
+export const AssetImage: FC<AssetImageProps> = ({ resolvedUrls, isLoading, imagePlaceholder, ...imgProps }) => {
+  const { url, isLoading: isResolving } = useGetAssetUrl(resolvedUrls, 'image')
+
+  const loading = isLoading || isResolving
+
+  return (
+    <SwitchTransition>
+      <CSSTransition
+        key={String(loading)}
+        timeout={parseInt(cVar('animationTimingFast', true))}
+        classNames={transitions.names.fade}
+      >
+        {loading ? (
+          <SkeletonLoader className={imgProps.className} />
+        ) : imagePlaceholder && !url ? (
+          <>{imagePlaceholder}</>
+        ) : (
+          <img {...imgProps} src={url} />
+        )}
+      </CSSTransition>
+    </SwitchTransition>
+  )
+}

+ 1 - 0
packages/atlas/src/components/AssetImage/index.ts

@@ -0,0 +1 @@
+export * from './AssetImage'

+ 19 - 0
packages/atlas/src/components/AssetVideo/AssetVideo.tsx

@@ -0,0 +1,19 @@
+import { VideoHTMLAttributes, forwardRef } from 'react'
+
+import { useGetAssetUrl } from '@/hooks/useGetAssetUrl'
+
+export type AssetVideoProps = {
+  resolvedVideoUrls: string[]
+  resolvedPosterUrls: string[]
+} & Omit<VideoHTMLAttributes<HTMLVideoElement>, 'src' | 'poster'>
+
+export const AssetVideo = forwardRef<HTMLVideoElement, AssetVideoProps>(
+  ({ resolvedVideoUrls, resolvedPosterUrls, ...props }: AssetVideoProps, ref) => {
+    const { url: videoSrc } = useGetAssetUrl(resolvedVideoUrls, 'video')
+    const { url: posterSrc } = useGetAssetUrl(resolvedPosterUrls, 'image')
+
+    return <video {...props} ref={ref} src={videoSrc} poster={posterSrc} />
+  }
+)
+
+AssetVideo.displayName = 'AssetVideo'

+ 1 - 1
packages/atlas/src/components/Avatar/Avatar.stories.tsx

@@ -6,7 +6,7 @@ export default {
   title: 'other/Avatar',
   title: 'other/Avatar',
   component: Avatar,
   component: Avatar,
   args: {
   args: {
-    assetUrl: 'https://picsum.photos/200/300',
+    assetUrls: ['https://picsum.photos/200/300'],
   },
   },
 } as Meta<AvatarProps>
 } as Meta<AvatarProps>
 
 

+ 2 - 22
packages/atlas/src/components/Avatar/Avatar.styles.ts

@@ -4,6 +4,7 @@ import styled from '@emotion/styled'
 
 
 import { SvgActionAddImage, SvgActionEdit, SvgIllustrativeFileFailed } from '@/assets/icons'
 import { SvgActionAddImage, SvgActionEdit, SvgIllustrativeFileFailed } from '@/assets/icons'
 import { SvgAvatarSilhouette } from '@/assets/illustrations'
 import { SvgAvatarSilhouette } from '@/assets/illustrations'
+import { AssetImage } from '@/components/AssetImage'
 import { SkeletonLoader } from '@/components/_loaders/SkeletonLoader'
 import { SkeletonLoader } from '@/components/_loaders/SkeletonLoader'
 import { cVar, square, zIndex } from '@/styles'
 import { cVar, square, zIndex } from '@/styles'
 
 
@@ -58,27 +59,6 @@ export const Overlay = styled.div<{ isEdit?: boolean }>`
     `};
     `};
 `
 `
 
 
-// const coverAvatarCss = css`
-//   ${square('64px')};
-
-//   ${media.md} {
-//     ${square('88px')};
-//   }
-// `
-
-// const channelAvatarCss = css`
-//   ${square('88px')};
-//   ${media.md} {
-//     ${square('136px')};
-//   }
-// `
-// const channelCardAvatarCss = css`
-//   ${square('88px')};
-//   ${media.md} {
-//     ${square('104px')};
-//   }
-// `
-
 export const sharedAvatarHoverStyles = (props: { disableHoverDimm?: boolean }) => css`
 export const sharedAvatarHoverStyles = (props: { disableHoverDimm?: boolean }) => css`
   ::after {
   ::after {
     border: 1px solid ${cVar('colorBackgroundAlpha')};
     border: 1px solid ${cVar('colorBackgroundAlpha')};
@@ -154,7 +134,7 @@ export const StyledSkeletonLoader = styled(SkeletonLoader)`
   left: 0;
   left: 0;
 `
 `
 
 
-export const StyledImage = styled.img`
+export const StyledImage = styled(AssetImage)`
   position: absolute;
   position: absolute;
   left: 0;
   left: 0;
   width: 100%;
   width: 100%;

+ 11 - 45
packages/atlas/src/components/Avatar/Avatar.tsx

@@ -1,9 +1,6 @@
-import { FC, MouseEvent, PropsWithChildren, useCallback, useEffect } from 'react'
-import { CSSTransition, SwitchTransition } from 'react-transition-group'
+import { FC, MouseEvent, PropsWithChildren, useCallback } from 'react'
 
 
 import { SvgActionNewChannel } from '@/assets/icons'
 import { SvgActionNewChannel } from '@/assets/icons'
-import { cVar, transitions } from '@/styles'
-import { validateImage } from '@/utils/image'
 
 
 import {
 import {
   AvatarSize,
   AvatarSize,
@@ -24,9 +21,8 @@ import { Text } from '../Text'
 
 
 export type AvatarProps = PropsWithChildren<{
 export type AvatarProps = PropsWithChildren<{
   onClick?: (event: MouseEvent<HTMLElement>) => void
   onClick?: (event: MouseEvent<HTMLElement>) => void
-  onImageValidation?: (validImage: boolean) => void
   onError?: () => void
   onError?: () => void
-  assetUrl?: string | null
+  assetUrls?: string[] | null
   hasAvatarUploadFailed?: boolean
   hasAvatarUploadFailed?: boolean
   loading?: boolean
   loading?: boolean
   className?: string
   className?: string
@@ -38,7 +34,7 @@ export type AvatarProps = PropsWithChildren<{
 }>
 }>
 
 
 export const Avatar: FC<AvatarProps> = ({
 export const Avatar: FC<AvatarProps> = ({
-  assetUrl,
+  assetUrls,
   hasAvatarUploadFailed,
   hasAvatarUploadFailed,
   loading = false,
   loading = false,
   size = 32,
   size = 32,
@@ -49,31 +45,10 @@ export const Avatar: FC<AvatarProps> = ({
   clickable,
   clickable,
   onError,
   onError,
   onClick,
   onClick,
-  onImageValidation,
   disableHoverDimm,
   disableHoverDimm,
 }) => {
 }) => {
   const isEditable = !loading && editable && size !== 32 && size !== 24
   const isEditable = !loading && editable && size !== 32 && size !== 24
 
 
-  const checkIfImageIsValid = useCallback(async () => {
-    if (!assetUrl) {
-      onImageValidation?.(true)
-      return
-    }
-    try {
-      await validateImage(assetUrl)
-      onImageValidation?.(true)
-    } catch (error) {
-      onImageValidation?.(false)
-    }
-  }, [assetUrl, onImageValidation])
-
-  useEffect(() => {
-    if (!assetUrl) {
-      return
-    }
-    checkIfImageIsValid()
-  }, [assetUrl, checkIfImageIsValid])
-
   const getEditableIconSize = useCallback(() => {
   const getEditableIconSize = useCallback(() => {
     const smallIconSizes = [24, 32, 40]
     const smallIconSizes = [24, 32, 40]
     if (smallIconSizes.includes(size)) {
     if (smallIconSizes.includes(size)) {
@@ -96,9 +71,9 @@ export const Avatar: FC<AvatarProps> = ({
     >
     >
       {(clickable || !!onClick) && (
       {(clickable || !!onClick) && (
         <IconAndOverlayWrapper>
         <IconAndOverlayWrapper>
-          <Overlay isEdit={isEditable && !!assetUrl} />
+          <Overlay isEdit={isEditable && !!assetUrls} />
           {isEditable &&
           {isEditable &&
-            (assetUrl ? (
+            (assetUrls ? (
               <StyledSvgActionEdit width={getEditableIconSize()} height={getEditableIconSize()} />
               <StyledSvgActionEdit width={getEditableIconSize()} height={getEditableIconSize()} />
             ) : (
             ) : (
               <StyledSvgActionAddImage width={getEditableIconSize()} height={getEditableIconSize()} />
               <StyledSvgActionAddImage width={getEditableIconSize()} height={getEditableIconSize()} />
@@ -120,21 +95,12 @@ export const Avatar: FC<AvatarProps> = ({
             )}
             )}
           </NewChannelAvatar>
           </NewChannelAvatar>
         ) : (
         ) : (
-          <SwitchTransition>
-            <CSSTransition
-              key={loading ? 'placeholder' : 'content'}
-              timeout={parseInt(cVar('animationTimingFast', true))}
-              classNames={transitions.names.fade}
-            >
-              {loading ? (
-                <StyledSkeletonLoader rounded />
-              ) : assetUrl ? (
-                <StyledImage src={assetUrl} onError={onError} />
-              ) : (
-                <SilhouetteAvatar />
-              )}
-            </CSSTransition>
-          </SwitchTransition>
+          <StyledImage
+            resolvedUrls={assetUrls}
+            onError={onError}
+            isLoading={loading}
+            imagePlaceholder={<SilhouetteAvatar />}
+          />
         ))}
         ))}
       {children && (loading ? <StyledSkeletonLoader rounded /> : <ChildrenWrapper>{children}</ChildrenWrapper>)}
       {children && (loading ? <StyledSkeletonLoader rounded /> : <ChildrenWrapper>{children}</ChildrenWrapper>)}
     </Container>
     </Container>

+ 4 - 4
packages/atlas/src/components/Avatar/AvatarGroup.stories.tsx

@@ -28,9 +28,9 @@ export const Default = Template.bind({})
 
 
 Default.args = {
 Default.args = {
   avatars: [
   avatars: [
-    { url: 'https://i.pravatar.cc/300', tooltipText: 'Jane' },
-    { url: 'https://i.pravatar.cc/300', tooltipText: 'John' },
-    { url: 'https://i.pravatar.cc/300', tooltipText: 'William' },
-    { url: 'https://i.pravatar.cc/300', tooltipText: 'One line description' },
+    { urls: ['https://i.pravatar.cc/300'], tooltipText: 'Jane' },
+    { urls: ['https://i.pravatar.cc/300'], tooltipText: 'John' },
+    { urls: ['https://i.pravatar.cc/300'], tooltipText: 'William' },
+    { urls: ['https://i.pravatar.cc/300'], tooltipText: 'One line description' },
   ],
   ],
 }
 }

+ 6 - 6
packages/atlas/src/components/Avatar/AvatarGroup.tsx

@@ -22,7 +22,7 @@ type SharedAvatarGroupAvatarProps = PropsWithChildren<{
 
 
 export type AvatarGroupUrlAvatar = {
 export type AvatarGroupUrlAvatar = {
   __typename?: 'AvatarGroupUrlAvatar'
   __typename?: 'AvatarGroupUrlAvatar'
-  url?: string | null
+  urls?: string[] | null
 } & SharedAvatarGroupAvatarProps
 } & SharedAvatarGroupAvatarProps
 
 
 type AvatarGroupMemberAvatar = BasicMembershipFieldsFragment & SharedAvatarGroupAvatarProps
 type AvatarGroupMemberAvatar = BasicMembershipFieldsFragment & SharedAvatarGroupAvatarProps
@@ -102,23 +102,23 @@ type SingleAvatarProps = {
   size: AvatarProps['size']
   size: AvatarProps['size']
 }
 }
 const SingleAvatar: FC<SingleAvatarProps> = ({ avatar, loading: loadingProp, size }) => {
 const SingleAvatar: FC<SingleAvatarProps> = ({ avatar, loading: loadingProp, size }) => {
-  const { url: memberAvatarUrl, isLoadingAsset: memberAvatarLoading } = getMemberAvatar(
+  const { urls: memberAvatarUrls, isLoadingAsset: memberAvatarLoading } = getMemberAvatar(
     avatar.__typename === 'Membership' ? avatar : null
     avatar.__typename === 'Membership' ? avatar : null
   )
   )
 
 
   let loading: boolean
   let loading: boolean
-  let url: string | null | undefined
+  let urls: string[] | null | undefined
   if (avatar.__typename === 'Membership') {
   if (avatar.__typename === 'Membership') {
-    url = memberAvatarUrl
+    urls = memberAvatarUrls
     loading = memberAvatarLoading || avatar.loading || loadingProp || false
     loading = memberAvatarLoading || avatar.loading || loadingProp || false
   } else {
   } else {
-    url = (avatar as AvatarGroupUrlAvatar).url
+    urls = (avatar as AvatarGroupUrlAvatar).urls
     loading = avatar.loading || loadingProp || false
     loading = avatar.loading || loadingProp || false
   }
   }
   return (
   return (
     <StyledAvatar
     <StyledAvatar
       loading={loading}
       loading={loading}
-      assetUrl={url}
+      assetUrls={urls}
       size={size}
       size={size}
       disableHoverDimm
       disableHoverDimm
       onClick={(e) => {
       onClick={(e) => {

+ 1 - 0
packages/atlas/src/components/Fee/Fee.tsx

@@ -49,6 +49,7 @@ export const Fee: FC<FeeProps> = ({
             variant={variant}
             variant={variant}
             color={loading ? 'colorTextMuted' : color}
             color={loading ? 'colorTextMuted' : color}
             withTooltip
             withTooltip
+            withDenomination="after"
             format="short"
             format="short"
             margin={{ right: 1 }}
             margin={{ right: 1 }}
           />
           />

+ 3 - 6
packages/atlas/src/components/MembershipInfo/MembershipInfo.tsx

@@ -14,11 +14,10 @@ import { CopyAddressButton } from '../_buttons/CopyAddressButton/CopyAddressButt
 import { SkeletonLoader } from '../_loaders/SkeletonLoader'
 import { SkeletonLoader } from '../_loaders/SkeletonLoader'
 
 
 export type MembershipInfoProps = {
 export type MembershipInfoProps = {
-  avatarUrl?: string | null
+  avatarUrls?: string[] | null
   avatarLoading?: boolean
   avatarLoading?: boolean
   hasAvatarUploadFailed?: boolean
   hasAvatarUploadFailed?: boolean
   onAvatarEditClick?: (event: MouseEvent<HTMLElement>) => void
   onAvatarEditClick?: (event: MouseEvent<HTMLElement>) => void
-  onImageValidation?: (validImage: boolean) => void
   handle?: string | null
   handle?: string | null
   address?: string | null
   address?: string | null
   loading?: boolean
   loading?: boolean
@@ -29,11 +28,10 @@ export type MembershipInfoProps = {
 
 
 export const MembershipInfo: FC<MembershipInfoProps> = ({
 export const MembershipInfo: FC<MembershipInfoProps> = ({
   address,
   address,
-  avatarUrl,
+  avatarUrls,
   avatarLoading,
   avatarLoading,
   hasAvatarUploadFailed,
   hasAvatarUploadFailed,
   onAvatarEditClick,
   onAvatarEditClick,
-  onImageValidation,
   handle,
   handle,
   loading,
   loading,
   isOwner,
   isOwner,
@@ -54,9 +52,8 @@ export const MembershipInfo: FC<MembershipInfoProps> = ({
             <Avatar
             <Avatar
               size={smMatch ? 136 : 88}
               size={smMatch ? 136 : 88}
               editable={editable}
               editable={editable}
-              onImageValidation={onImageValidation}
               onClick={onAvatarEditClick}
               onClick={onAvatarEditClick}
-              assetUrl={avatarUrl}
+              assetUrls={avatarUrls}
               loading={avatarLoading}
               loading={avatarLoading}
               hasAvatarUploadFailed={hasAvatarUploadFailed}
               hasAvatarUploadFailed={hasAvatarUploadFailed}
             />
             />

+ 3 - 1
packages/atlas/src/components/MinimizedPlayer/MinimizedPlayer.tsx

@@ -15,6 +15,7 @@ type MiniVideoProps = {
 export const MinimizedPlayer = forwardRef<HTMLVideoElement, MiniVideoProps>(
 export const MinimizedPlayer = forwardRef<HTMLVideoElement, MiniVideoProps>(
   ({ isInView, author, title, ...videoPlayerProps }, ref) => {
   ({ isInView, author, title, ...videoPlayerProps }, ref) => {
     const [forceExit, setForceExit] = useState(false)
     const [forceExit, setForceExit] = useState(false)
+    const [hasError, setHasError] = useState(false)
     const [isPaused, setIsPaused] = useState(false)
     const [isPaused, setIsPaused] = useState(false)
     const [wasPausedOnTop, setWasPausedTop] = useState(false)
     const [wasPausedOnTop, setWasPausedTop] = useState(false)
     const isAllowed = usePersonalDataStore((state) => state.allowMinimizedPleyer)
     const isAllowed = usePersonalDataStore((state) => state.allowMinimizedPleyer)
@@ -27,7 +28,7 @@ export const MinimizedPlayer = forwardRef<HTMLVideoElement, MiniVideoProps>(
       }
       }
     }, [isInView, isPaused])
     }, [isInView, isPaused])
 
 
-    const inView = isAllowed && mdMatch && !wasPausedOnTop ? isInView || forceExit : true
+    const inView = isAllowed && mdMatch && !wasPausedOnTop ? isInView || forceExit || hasError : true
 
 
     return (
     return (
       <Wrapper isInView={inView}>
       <Wrapper isInView={inView}>
@@ -42,6 +43,7 @@ export const MinimizedPlayer = forwardRef<HTMLVideoElement, MiniVideoProps>(
             setIsPaused(false)
             setIsPaused(false)
             videoPlayerProps.onPlay?.()
             videoPlayerProps.onPlay?.()
           }}
           }}
+          onError={() => setHasError(true)}
           onMinimizedExit={() => setForceExit(true)}
           onMinimizedExit={() => setForceExit(true)}
           {...videoPlayerProps}
           {...videoPlayerProps}
         />
         />

+ 20 - 17
packages/atlas/src/components/NftCarousel/components/MarketplaceCarouselCard/NftCarouselDetails.tsx

@@ -6,7 +6,7 @@ import { CSSTransition } from 'react-transition-group'
 import { getNftStatus } from '@/api/hooks/nfts'
 import { getNftStatus } from '@/api/hooks/nfts'
 import { GetFeaturedNftsVideosQuery } from '@/api/queries/__generated__/nfts.generated'
 import { GetFeaturedNftsVideosQuery } from '@/api/queries/__generated__/nfts.generated'
 import { SvgActionNotForSale } from '@/assets/icons'
 import { SvgActionNotForSale } from '@/assets/icons'
-import { AvatarGroup } from '@/components/Avatar/AvatarGroup'
+import { AvatarGroup, AvatarGroupAvatar } from '@/components/Avatar/AvatarGroup'
 import { JoyTokenIcon } from '@/components/JoyTokenIcon'
 import { JoyTokenIcon } from '@/components/JoyTokenIcon'
 import {
 import {
   Container,
   Container,
@@ -43,34 +43,34 @@ export const NftCarouselDetails = ({
   const { convertBlockToMsTimestamp } = useBlockTimeEstimation()
   const { convertBlockToMsTimestamp } = useBlockTimeEstimation()
   const nftStatus = getNftStatus(nft, nft?.video)
   const nftStatus = getNftStatus(nft, nft?.video)
 
 
-  const creatorAvatarUrl =
+  const creatorAvatarUrls =
     nft.owner.__typename === 'NftOwnerChannel'
     nft.owner.__typename === 'NftOwnerChannel'
-      ? nft.owner.channel.avatarPhoto?.resolvedUrl
-      : getMemberAvatar(nft.owner.member).url
-  const thumbnailUrl = nft.video.thumbnailPhoto?.resolvedUrl
-  const mediaUrl = nft.video.media?.resolvedUrl
+      ? nft.owner.channel.avatarPhoto?.resolvedUrls
+      : getMemberAvatar(nft.owner.member).urls
+  const thumbnailUrls = nft.video.thumbnailPhoto?.resolvedUrls
+  const mediaUrls = nft.video.media?.resolvedUrls
   const plannedEndDateBlockTimestamp =
   const plannedEndDateBlockTimestamp =
     nftStatus?.status === 'auction' &&
     nftStatus?.status === 'auction' &&
     nftStatus.auctionPlannedEndBlock &&
     nftStatus.auctionPlannedEndBlock &&
     convertBlockToMsTimestamp(nftStatus.auctionPlannedEndBlock)
     convertBlockToMsTimestamp(nftStatus.auctionPlannedEndBlock)
-  const isLoading = !thumbnailUrl || !mediaUrl
+  const isLoading = !thumbnailUrls || !mediaUrls
   const name = nft.owner.__typename === 'NftOwnerChannel' ? nft.video.channel.title : nft.owner.member.handle
   const name = nft.owner.__typename === 'NftOwnerChannel' ? nft.video.channel.title : nft.owner.member.handle
   const owner = useMemo(
   const owner = useMemo(
     () =>
     () =>
       nft?.owner.__typename === 'NftOwnerChannel'
       nft?.owner.__typename === 'NftOwnerChannel'
         ? {
         ? {
             name,
             name,
-            assetUrl: creatorAvatarUrl,
+            assetUrls: creatorAvatarUrls,
             onClick: () => navigate(absoluteRoutes.viewer.channel(nft.video.channel.id)),
             onClick: () => navigate(absoluteRoutes.viewer.channel(nft.video.channel.id)),
           }
           }
         : nft?.owner.__typename === 'NftOwnerMember'
         : nft?.owner.__typename === 'NftOwnerMember'
         ? {
         ? {
             name,
             name,
-            assetUrl: creatorAvatarUrl,
+            assetUrls: creatorAvatarUrls,
             onClick: () => name && navigate(absoluteRoutes.viewer.member(name)),
             onClick: () => name && navigate(absoluteRoutes.viewer.member(name)),
           }
           }
         : undefined,
         : undefined,
-    [creatorAvatarUrl, name, navigate, nft]
+    [creatorAvatarUrls, name, navigate, nft]
   )
   )
 
 
   const nftDetails = useMemo(
   const nftDetails = useMemo(
@@ -83,7 +83,7 @@ export const NftCarouselDetails = ({
           : undefined,
           : undefined,
       creator: {
       creator: {
         name: nft?.video.channel.title || undefined,
         name: nft?.video.channel.title || undefined,
-        assetUrl: creatorAvatarUrl,
+        assetUrl: creatorAvatarUrls,
         onClick: () => navigate(absoluteRoutes.viewer.channel(nft?.video.channel.id)),
         onClick: () => navigate(absoluteRoutes.viewer.channel(nft?.video.channel.id)),
       },
       },
       title: nft.video.title,
       title: nft.video.title,
@@ -97,20 +97,20 @@ export const NftCarouselDetails = ({
           ? hapiBnToTokenNumber(nftStatus.startingPrice)
           ? hapiBnToTokenNumber(nftStatus.startingPrice)
           : undefined,
           : undefined,
     }),
     }),
-    [creatorAvatarUrl, navigate, nft, nftStatus]
+    [creatorAvatarUrls, navigate, nft, nftStatus]
   )
   )
 
 
   const avatars = useMemo(
   const avatars = useMemo(
-    () => [
+    (): AvatarGroupAvatar[] => [
       {
       {
-        url: nftDetails.creator?.assetUrl,
+        urls: nftDetails.creator?.assetUrl,
         tooltipText: `Creator: ${nftDetails.creator?.name}`,
         tooltipText: `Creator: ${nftDetails.creator?.name}`,
         onClick: nftDetails.creator?.onClick,
         onClick: nftDetails.creator?.onClick,
       },
       },
       ...(owner
       ...(owner
         ? [
         ? [
             {
             {
-              url: owner?.assetUrl,
+              urls: owner?.assetUrls,
               tooltipText: `Owner: ${owner?.name}`,
               tooltipText: `Owner: ${owner?.name}`,
               onClick: owner?.onClick,
               onClick: owner?.onClick,
             },
             },
@@ -168,8 +168,8 @@ export const NftCarouselDetails = ({
           onPause={() => setIsPaused(true)}
           onPause={() => setIsPaused(true)}
           onPlay={() => setIsPaused(false)}
           onPlay={() => setIsPaused(false)}
           preload="auto"
           preload="auto"
-          src={mediaUrl ?? undefined}
-          poster={thumbnailUrl ?? undefined}
+          src={mediaUrls ?? undefined}
+          poster={thumbnailUrls ?? undefined}
           handleActions={active}
           handleActions={active}
           videoPlaytime={30}
           videoPlaytime={30}
           onEnded={slideNext}
           onEnded={slideNext}
@@ -191,6 +191,7 @@ export const NftCarouselDetails = ({
                     caption="BUY NOW"
                     caption="BUY NOW"
                     content={nftDetails.buyNow}
                     content={nftDetails.buyNow}
                     icon={<JoyTokenIcon size={smMatch ? 24 : 16} variant="silver" />}
                     icon={<JoyTokenIcon size={smMatch ? 24 : 16} variant="silver" />}
+                    withDenomination
                   />
                   />
                 )}
                 )}
                 {nftDetails.topBid && (
                 {nftDetails.topBid && (
@@ -200,6 +201,7 @@ export const NftCarouselDetails = ({
                     caption="TOP BID"
                     caption="TOP BID"
                     content={nftDetails.topBid}
                     content={nftDetails.topBid}
                     icon={<JoyTokenIcon size={smMatch ? 24 : 16} variant="silver" />}
                     icon={<JoyTokenIcon size={smMatch ? 24 : 16} variant="silver" />}
+                    withDenomination
                   />
                   />
                 )}
                 )}
                 {nftDetails.minBid && (
                 {nftDetails.minBid && (
@@ -209,6 +211,7 @@ export const NftCarouselDetails = ({
                     caption="MIN BID"
                     caption="MIN BID"
                     content={nftDetails.minBid}
                     content={nftDetails.minBid}
                     icon={<JoyTokenIcon size={smMatch ? 24 : 16} variant="silver" />}
                     icon={<JoyTokenIcon size={smMatch ? 24 : 16} variant="silver" />}
+                    withDenomination
                   />
                   />
                 )}
                 )}
                 {nftStatus?.status === 'idle' && (
                 {nftStatus?.status === 'idle' && (

+ 130 - 12
packages/atlas/src/components/NumberFormat/NumberFormat.tsx

@@ -1,11 +1,14 @@
+import { css } from '@emotion/react'
 import styled from '@emotion/styled'
 import styled from '@emotion/styled'
 import BN from 'bn.js'
 import BN from 'bn.js'
-import { forwardRef, useRef } from 'react'
+import { ReactNode, forwardRef, useRef } from 'react'
 import { mergeRefs } from 'react-merge-refs'
 import { mergeRefs } from 'react-merge-refs'
 
 
 import { Text, TextProps, TextVariant } from '@/components/Text'
 import { Text, TextProps, TextVariant } from '@/components/Text'
 import { atlasConfig } from '@/config'
 import { atlasConfig } from '@/config'
 import { hapiBnToTokenNumber } from '@/joystream-lib/utils'
 import { hapiBnToTokenNumber } from '@/joystream-lib/utils'
+import { useTokenPrice } from '@/providers/joystream/joystream.hooks'
+import { sizes } from '@/styles'
 import { formatNumber } from '@/utils/number'
 import { formatNumber } from '@/utils/number'
 
 
 import { Tooltip } from '../Tooltip'
 import { Tooltip } from '../Tooltip'
@@ -19,8 +22,13 @@ export type NumberFormatProps = {
   variant?: TextVariant
   variant?: TextVariant
   displayedValue?: string | number
   displayedValue?: string | number
   isNegative?: boolean
   isNegative?: boolean
+  icon?: ReactNode
+  withDenomination?: boolean | 'horizontal' | 'vertical' | 'before' | 'after'
+  denominationAlign?: 'left' | 'right'
 } & Omit<TextProps, 'children' | 'variant'>
 } & Omit<TextProps, 'children' | 'variant'>
 
 
+const TEXT_DENOMINATION_ALIGNMENTS: NumberFormatProps['withDenomination'][] = ['before', 'after']
+
 export const NumberFormat = forwardRef<HTMLHeadingElement, NumberFormatProps>(
 export const NumberFormat = forwardRef<HTMLHeadingElement, NumberFormatProps>(
   (
   (
     {
     {
@@ -32,25 +40,37 @@ export const NumberFormat = forwardRef<HTMLHeadingElement, NumberFormatProps>(
       displayedValue,
       displayedValue,
       isNegative,
       isNegative,
       color,
       color,
+      withDenomination: _withDenomination,
+      denominationAlign = 'left',
+      icon,
       ...textProps
       ...textProps
     },
     },
     ref
     ref
   ) => {
   ) => {
+    const withDenomination = atlasConfig.joystream.tokenPriceFeedUrl ? _withDenomination : undefined
+    const { convertTokensToUSD } = useTokenPrice()
     const internalValue = BN.isBN(value) ? hapiBnToTokenNumber(value) : value
     const internalValue = BN.isBN(value) ? hapiBnToTokenNumber(value) : value
+    const fiatValue = convertTokensToUSD(internalValue)
     const textRef = useRef<HTMLHeadingElement>(null)
     const textRef = useRef<HTMLHeadingElement>(null)
+    const denominationRef = useRef<HTMLHeadingElement>(null)
     const bnValue = new BN(value)
     const bnValue = new BN(value)
     let formattedValue
     let formattedValue
+    let formattedDenominatedValue
     let tooltipText
     let tooltipText
     switch (isNegative || bnValue.isNeg() ? 'full' : format) {
     switch (isNegative || bnValue.isNeg() ? 'full' : format) {
       case 'short':
       case 'short':
-        formattedValue = internalValue ? (internalValue > 0.01 ? formatNumberShort(internalValue) : `< 0.01`) : 0
+        formattedValue = internalValue ? (internalValue > 0.01 ? formatNumberShort(internalValue) : `<0.01`) : 0
+        formattedDenominatedValue = fiatValue ? (fiatValue > 0.01 ? formatNumberShort(fiatValue) : `<$0.01`) : 0
         tooltipText = formatNumber(internalValue)
         tooltipText = formatNumber(internalValue)
         break
         break
       case 'full':
       case 'full':
         formattedValue = tooltipText = formatNumber(internalValue)
         formattedValue = tooltipText = formatNumber(internalValue)
+        formattedDenominatedValue = fiatValue ? formatNumber(fiatValue) : 0
         break
         break
       case 'dollar':
       case 'dollar':
         formattedValue = formatDollars(internalValue)
         formattedValue = formatDollars(internalValue)
+        formattedDenominatedValue = fiatValue ? formatDollars(fiatValue) : 0
+
         tooltipText = new Intl.NumberFormat('en-US', { maximumSignificantDigits, ...currencyFormatOptions })
         tooltipText = new Intl.NumberFormat('en-US', { maximumSignificantDigits, ...currencyFormatOptions })
           .format(internalValue)
           .format(internalValue)
           .replaceAll(',', ' ')
           .replaceAll(',', ' ')
@@ -61,32 +81,130 @@ export const NumberFormat = forwardRef<HTMLHeadingElement, NumberFormatProps>(
     const hasTooltip =
     const hasTooltip =
       withTooltip &&
       withTooltip &&
       ((format === 'short' && (internalValue > 999 || hasDecimals)) || (format === 'dollar' && hasDecimals))
       ((format === 'short' && (internalValue > 999 || hasDecimals)) || (format === 'dollar' && hasDecimals))
+    const shouldShowDenominationTooltip = fiatValue && fiatValue <= 0.01
     const content = (
     const content = (
-      <StyledText
-        {...textProps}
-        color={bnValue.isNeg() || isNegative ? 'colorTextError' : color}
-        variant={variant}
-        ref={mergeRefs([ref, textRef])}
-      >
-        {displayedValue || formattedValue}
-        {withToken && ` ${atlasConfig.joystream.tokenTicker}`}
-      </StyledText>
+      <ContentContainer>
+        {withDenomination === 'before' && (
+          <Text
+            className="denomination"
+            as="span"
+            color={bnValue.isNeg() || isNegative ? 'colorTextError' : 'colorTextMuted'}
+            variant={variant}
+            ref={denominationRef}
+          >
+            ({formattedDenominatedValue !== '<$0.01' ? '$' : ''}
+            {formattedDenominatedValue}){' '}
+          </Text>
+        )}
+        <StyledText
+          {...textProps}
+          color={bnValue.isNeg() || isNegative ? 'colorTextError' : color}
+          variant={variant}
+          ref={mergeRefs([ref, textRef])}
+        >
+          {displayedValue || formattedValue}
+          {withToken && ` ${atlasConfig.joystream.tokenTicker}`}
+        </StyledText>
+        {withDenomination === 'after' && (
+          <Text
+            className="denomination"
+            as="span"
+            color={bnValue.isNeg() || isNegative ? 'colorTextError' : 'colorTextMuted'}
+            variant={variant}
+            ref={denominationRef}
+          >
+            {' '}
+            ({formattedDenominatedValue !== '<$0.01' ? '$' : ''}
+            {formattedDenominatedValue}){' '}
+          </Text>
+        )}
+      </ContentContainer>
     )
     )
 
 
     return (
     return (
       <>
       <>
-        {content}
+        {withDenomination ? (
+          <Container orientation={withDenomination}>
+            {icon ? (
+              <IconContainer>
+                {icon}
+                {content}
+              </IconContainer>
+            ) : (
+              content
+            )}
+            {!TEXT_DENOMINATION_ALIGNMENTS.includes(withDenomination) && (
+              <Denomination
+                align={denominationAlign}
+                className="denomination"
+                as="span"
+                color={bnValue.isNeg() || isNegative ? 'colorTextError' : 'colorTextMuted'}
+                variant="t100"
+                ref={denominationRef}
+              >
+                {formattedDenominatedValue !== '<$0.01' ? '$' : ''}
+                {formattedDenominatedValue}
+              </Denomination>
+            )}
+          </Container>
+        ) : icon ? (
+          <IconContainer>
+            {icon}
+            {content}
+          </IconContainer>
+        ) : (
+          content
+        )}
+
         <Tooltip reference={textRef} placement="top" delay={[500, null]} text={hasTooltip ? tooltipText : undefined} />
         <Tooltip reference={textRef} placement="top" delay={[500, null]} text={hasTooltip ? tooltipText : undefined} />
+        <Tooltip
+          reference={denominationRef}
+          placement="top"
+          delay={[500, null]}
+          text={shouldShowDenominationTooltip ? `$${fiatValue?.toPrecision(2)}` : undefined}
+        />
       </>
       </>
     )
     )
   }
   }
 )
 )
 NumberFormat.displayName = 'Number'
 NumberFormat.displayName = 'Number'
 
 
+export const ContentContainer = styled.div`
+  display: inline-block;
+`
+
 const StyledText = styled(Text)`
 const StyledText = styled(Text)`
   display: inline-block;
   display: inline-block;
 `
 `
 
 
+const Denomination = styled(Text)<{ align: 'right' | 'left' }>`
+  display: inline-block;
+  text-align: ${(props) => props.align};
+`
+
+const Container = styled.div<{ orientation: NumberFormatProps['withDenomination'] }>`
+  display: flex;
+  flex-direction: column;
+  gap: ${sizes(1)};
+  width: fit-content;
+  ${(props) =>
+    props.orientation === 'horizontal' &&
+    css`
+      width: 100%;
+      flex-direction: row;
+      align-items: center;
+      justify-content: space-between;
+    `}
+`
+
+const IconContainer = styled.div`
+  display: inline-grid;
+  grid-auto-flow: column;
+  grid-auto-columns: max-content;
+  align-items: center;
+  gap: ${sizes(1)};
+`
+
 const maximumSignificantDigits = 21
 const maximumSignificantDigits = 21
 
 
 const currencyFormatOptions = {
 const currencyFormatOptions = {

+ 1 - 1
packages/atlas/src/components/OutputPill/OutputPill.stories.tsx

@@ -6,7 +6,7 @@ export default {
   title: 'Other/OutputPill',
   title: 'Other/OutputPill',
   component: OutputPill,
   component: OutputPill,
   args: {
   args: {
-    avatarUri: 'https://placedog.net/100/100',
+    avatarUrls: ['https://placedog.net/100/100'],
     handle: 'Member',
     handle: 'Member',
     withAvatar: true,
     withAvatar: true,
     readonly: false,
     readonly: false,

+ 3 - 3
packages/atlas/src/components/OutputPill/OutputPill.tsx

@@ -5,7 +5,7 @@ import { Text } from '@/components/Text'
 import { OutputPillWrapper, RemoveButton, StyledAvatar, StyledSVGCloseIcon } from './OutputPill.styles'
 import { OutputPillWrapper, RemoveButton, StyledAvatar, StyledSVGCloseIcon } from './OutputPill.styles'
 
 
 export type OutputPillProps = {
 export type OutputPillProps = {
-  avatarUri?: string | null
+  avatarUrls?: string[] | null
   handle?: string | null
   handle?: string | null
   onDeleteClick?: () => void
   onDeleteClick?: () => void
   className?: string
   className?: string
@@ -16,7 +16,7 @@ export type OutputPillProps = {
   onKeyPress?: (event: KeyboardEvent<HTMLButtonElement>) => void
   onKeyPress?: (event: KeyboardEvent<HTMLButtonElement>) => void
 }
 }
 export const OutputPill: FC<OutputPillProps> = ({
 export const OutputPill: FC<OutputPillProps> = ({
-  avatarUri,
+  avatarUrls,
   handle,
   handle,
   onDeleteClick,
   onDeleteClick,
   className,
   className,
@@ -35,7 +35,7 @@ export const OutputPill: FC<OutputPillProps> = ({
 
 
   return (
   return (
     <OutputPillWrapper className={className} withoutButton={!onDeleteClick || readonly}>
     <OutputPillWrapper className={className} withoutButton={!onDeleteClick || readonly}>
-      {withAvatar && <StyledAvatar size={24} assetUrl={avatarUri} loading={isLoadingAvatar} />}
+      {withAvatar && <StyledAvatar size={24} assetUrls={avatarUrls} loading={isLoadingAvatar} />}
       <Text variant="t200" as="p">
       <Text variant="t200" as="p">
         {handle}
         {handle}
       </Text>
       </Text>

+ 1 - 1
packages/atlas/src/components/OwnerPill/OwnerPill.tsx

@@ -7,7 +7,7 @@ import { Avatar } from '../Avatar'
 export type OwnerPillProps = {
 export type OwnerPillProps = {
   handle?: string
   handle?: string
   avatar?: {
   avatar?: {
-    assetUrl?: string | null
+    assetUrls?: string[] | null
     loading?: boolean
     loading?: boolean
   }
   }
   title?: string
   title?: string

+ 8 - 4
packages/atlas/src/components/Searchbar/SearchBox/Result.tsx

@@ -3,6 +3,7 @@ import { FC, useCallback, useMemo } from 'react'
 import { BasicChannelFieldsFragment, BasicVideoFieldsFragment } from '@/api/queries/__generated__/fragments.generated'
 import { BasicChannelFieldsFragment, BasicVideoFieldsFragment } from '@/api/queries/__generated__/fragments.generated'
 import { Text } from '@/components/Text'
 import { Text } from '@/components/Text'
 import { absoluteRoutes } from '@/config/routes'
 import { absoluteRoutes } from '@/config/routes'
+import { useGetAssetUrl } from '@/hooks/useGetAssetUrl'
 
 
 import { ResultTitle } from './ResultTitle'
 import { ResultTitle } from './ResultTitle'
 import { ResultWrapper } from './ResultWrapper'
 import { ResultWrapper } from './ResultWrapper'
@@ -34,8 +35,11 @@ export const Result: FC<ResultProps> = ({
   loading,
   loading,
 }) => {
 }) => {
   const title = video ? video.title : channel?.title
   const title = video ? video.title : channel?.title
-  const channelAvatar = channel?.avatarPhoto?.resolvedUrl
-  const videoThumbnail = video?.thumbnailPhoto?.resolvedUrl
+  const { url: channelAvatar, isLoading: isLoadingAvatar } = useGetAssetUrl(channel?.avatarPhoto?.resolvedUrls, 'image')
+  const { url: videoThumbnail, isLoading: isLoadingThumbnail } = useGetAssetUrl(
+    video?.thumbnailPhoto?.resolvedUrls,
+    'image'
+  )
   const to = useMemo(() => {
   const to = useMemo(() => {
     if (video) {
     if (video) {
       return absoluteRoutes.viewer.video(video.id)
       return absoluteRoutes.viewer.video(video.id)
@@ -58,12 +62,12 @@ export const Result: FC<ResultProps> = ({
   return (
   return (
     <ResultWrapper to={to} selected={selected} handleSelectedItem={onSelected} selectedItem={selectedItem}>
     <ResultWrapper to={to} selected={selected} handleSelectedItem={onSelected} selectedItem={selectedItem}>
       <ResultContent>
       <ResultContent>
-        {loading ? (
+        {loading && (video ? isLoadingThumbnail : isLoadingAvatar) ? (
           <StyledSkeletonLoader width={video ? '64px' : '32px'} height={video ? '40px' : '32px'} rounded={!!channel} />
           <StyledSkeletonLoader width={video ? '64px' : '32px'} height={video ? '40px' : '32px'} rounded={!!channel} />
         ) : channel && !thumbnailUrl ? (
         ) : channel && !thumbnailUrl ? (
           <StyledSvgAvatarSilhouette width={32} height={32} />
           <StyledSvgAvatarSilhouette width={32} height={32} />
         ) : (
         ) : (
-          <ResultThumbnail src={thumbnailUrl || ''} rounded={!!channel} />
+          <ResultThumbnail src={thumbnailUrl} rounded={!!channel} />
         )}
         )}
         <div>
         <div>
           <Title as="span" color={!selected ? 'colorText' : undefined} variant="t200-strong">
           <Title as="span" color={!selected ? 'colorText' : undefined} variant="t200-strong">

+ 9 - 0
packages/atlas/src/components/Searchbar/Searchbar.styles.ts

@@ -80,6 +80,12 @@ export const InnerContainer = styled.div<{ hasFocus: boolean; hasQuery: boolean
   }
   }
 `
 `
 
 
+export const StyledButton = styled(Button)`
+  width: 100% !important;
+  height: 100% !important;
+  border-radius: unset !important;
+`
+
 export const StyledSvgOutlineSearch = styled(SvgControlsSearchAlt, { shouldForwardProp: isPropValid })<{
 export const StyledSvgOutlineSearch = styled(SvgControlsSearchAlt, { shouldForwardProp: isPropValid })<{
   highlighted?: boolean
   highlighted?: boolean
 }>`
 }>`
@@ -104,6 +110,9 @@ export const SearchHelper = styled(Text)`
 export const SearchButton = styled(Button)`
 export const SearchButton = styled(Button)`
   padding: 0;
   padding: 0;
   margin: 0 auto;
   margin: 0 auto;
+  width: 100%;
+  height: 100%;
+  border-radius: unset;
 
 
   ${media.md} {
   ${media.md} {
     display: none;
     display: none;

+ 4 - 4
packages/atlas/src/components/Section/Section.stories.tsx

@@ -262,7 +262,7 @@ const CarouselTemplate: StoryFn<SectionProps<unknown>> = () => {
               <VideoTile
               <VideoTile
                 loadingDetails={true}
                 loadingDetails={true}
                 loadingAvatar={true}
                 loadingAvatar={true}
-                thumbnailUrl={`http://placekitten.com/g/${320 + idx}/180`}
+                thumbnailUrls={[`http://placekitten.com/g/${320 + idx}/180`]}
               />
               />
             </RankingNumberTile>
             </RankingNumberTile>
           )),
           )),
@@ -286,7 +286,7 @@ const CarouselTemplate: StoryFn<SectionProps<unknown>> = () => {
               <VideoTile
               <VideoTile
                 loadingDetails={true}
                 loadingDetails={true}
                 loadingAvatar={true}
                 loadingAvatar={true}
-                thumbnailUrl={`https://place.dog/${320 + idx}/180`}
+                thumbnailUrls={[`https://place.dog/${320 + idx}/180`]}
               />
               />
             </RankingNumberTile>
             </RankingNumberTile>
           )),
           )),
@@ -308,7 +308,7 @@ const CarouselTemplate: StoryFn<SectionProps<unknown>> = () => {
           children: placeholderItems.map((_, idx) => (
           children: placeholderItems.map((_, idx) => (
             <NftTile
             <NftTile
               key={idx}
               key={idx}
-              thumbnail={{ type: 'video', thumbnailUrl: `https://place.dog/${320 + idx}/180` }}
+              thumbnail={{ type: 'video', thumbnailUrls: [`https://place.dog/${320 + idx}/180`] }}
               title={`Nft number ${idx}`}
               title={`Nft number ${idx}`}
             />
             />
           )),
           )),
@@ -332,7 +332,7 @@ const CarouselTemplate: StoryFn<SectionProps<unknown>> = () => {
               key={idx}
               key={idx}
               loadingDetails={true}
               loadingDetails={true}
               loadingAvatar={true}
               loadingAvatar={true}
-              thumbnailUrl={`https://place.dog/${320 + idx}/180`}
+              thumbnailUrls={[`https://place.dog/${320 + idx}/180`]}
             />
             />
           )),
           )),
         }}
         }}

+ 1 - 1
packages/atlas/src/components/Section/SectionHeader/SectionHeader.stories.tsx

@@ -215,7 +215,7 @@ const WithTitleTemplate: StoryFn<SectionHeaderProps<unknown>> = () => {
           nodeStart: {
           nodeStart: {
             type: 'avatar',
             type: 'avatar',
             avatarProps: {
             avatarProps: {
-              assetUrl: 'https://placekitten.com/g/200/300',
+              assetUrls: ['https://placekitten.com/g/200/300'],
             },
             },
           },
           },
         }}
         }}

+ 3 - 0
packages/atlas/src/components/Table/Table.styles.ts

@@ -43,6 +43,9 @@ export const Th = styled(Text)`
 export const Td = styled(Text)`
 export const Td = styled(Text)`
   ${cellStyles};
   ${cellStyles};
 
 
+  align-items: start;
+  flex-direction: column;
+  justify-content: center;
   box-shadow: ${cVar('effectDividersBottom')};
   box-shadow: ${cVar('effectDividersBottom')};
 `
 `
 
 

+ 11 - 14
packages/atlas/src/components/TablePaymentsHistory/TablePaymentsHistory.tsx

@@ -18,7 +18,6 @@ import { formatDateTime } from '@/utils/time'
 
 
 import {
 import {
   DialogText,
   DialogText,
-  JoyAmountWrapper,
   JoystreamSvgWrapper,
   JoystreamSvgWrapper,
   SenderItem,
   SenderItem,
   StyledJoyTokenIcon,
   StyledJoyTokenIcon,
@@ -116,7 +115,7 @@ const Sender = ({ sender }: { sender: PaymentHistory['sender'] }) => {
     }
     }
   )
   )
   const member = memberships?.find((member) => member.controllerAccount === sender)
   const member = memberships?.find((member) => member.controllerAccount === sender)
-  const { url: avatarUrl, isLoadingAsset: avatarLoading } = getMemberAvatar(member)
+  const { urls: avatarUrls, isLoadingAsset: avatarLoading } = getMemberAvatar(member)
 
 
   if (sender === 'council') {
   if (sender === 'council') {
     return (
     return (
@@ -135,7 +134,7 @@ const Sender = ({ sender }: { sender: PaymentHistory['sender'] }) => {
     return (
     return (
       <StyledLink to={absoluteRoutes.viewer.member(member.handle)}>
       <StyledLink to={absoluteRoutes.viewer.member(member.handle)}>
         <SenderItem
         <SenderItem
-          nodeStart={<Avatar assetUrl={avatarUrl} size={32} loading={avatarLoading} />}
+          nodeStart={<Avatar assetUrls={avatarUrls} size={32} loading={avatarLoading} />}
           label={member?.handle}
           label={member?.handle}
           isInteractive={false}
           isInteractive={false}
         />
         />
@@ -174,16 +173,14 @@ const Type = ({ type }: { type: PaymentType }) => {
 const TokenAmount = ({ tokenAmount }: { tokenAmount: BN }) => {
 const TokenAmount = ({ tokenAmount }: { tokenAmount: BN }) => {
   const isNegative = tokenAmount.isNeg()
   const isNegative = tokenAmount.isNeg()
   return (
   return (
-    <JoyAmountWrapper>
-      <StyledJoyTokenIcon variant="gray" error={isNegative} />
-      <StyledNumberFormat
-        variant="t200-strong"
-        as="p"
-        value={tokenAmount}
-        margin={{ left: 1 }}
-        format="short"
-        color={isNegative ? 'colorTextError' : 'colorTextStrong'}
-      />
-    </JoyAmountWrapper>
+    <StyledNumberFormat
+      icon={<StyledJoyTokenIcon variant="gray" error={isNegative} />}
+      variant="t200-strong"
+      as="p"
+      value={tokenAmount}
+      format="short"
+      color={isNegative ? 'colorTextError' : 'colorTextStrong'}
+      withDenomination
+    />
   )
   )
 }
 }

+ 4 - 2
packages/atlas/src/components/TopSellingChannelsTable/TopSellingChannelsTable.tsx

@@ -100,13 +100,15 @@ export const TopSellingChannelsTable = () => {
           ),
           ),
           salesVolume: (
           salesVolume: (
             <JoyAmountWrapper>
             <JoyAmountWrapper>
-              <JoyTokenIcon variant="gray" />
               <NumberFormat
               <NumberFormat
+                icon={<JoyTokenIcon variant="gray" />}
                 variant="t200-strong"
                 variant="t200-strong"
                 as="p"
                 as="p"
                 value={new BN(data.amount)}
                 value={new BN(data.amount)}
                 margin={{ left: 1 }}
                 margin={{ left: 1 }}
                 format="short"
                 format="short"
+                withDenomination
+                denominationAlign="right"
               />
               />
             </JoyAmountWrapper>
             </JoyAmountWrapper>
           ),
           ),
@@ -199,7 +201,7 @@ const Channel = ({ channel }: { channel: BasicChannelFieldsFragment }) => {
   return (
   return (
     <StyledLink to={absoluteRoutes.viewer.channel(channel.id)} title={channel.title || ''}>
     <StyledLink to={absoluteRoutes.viewer.channel(channel.id)} title={channel.title || ''}>
       <StyledListItem
       <StyledListItem
-        nodeStart={<Avatar assetUrl={channel.avatarPhoto?.resolvedUrl ?? undefined} />}
+        nodeStart={<Avatar assetUrls={channel.avatarPhoto?.resolvedUrls ?? undefined} />}
         label={channel.title}
         label={channel.title}
         isInteractive={false}
         isInteractive={false}
         nodeEnd={
         nodeEnd={

+ 1 - 1
packages/atlas/src/components/WidgetTile/WidgetTile.styles.ts

@@ -24,7 +24,7 @@ export const Content = styled.div`
   align-self: flex-end;
   align-self: flex-end;
   gap: ${sizes(4)};
   gap: ${sizes(4)};
 
 
-  ${media.lg} {
+  ${media.md} {
     gap: ${sizes(6)};
     gap: ${sizes(6)};
     grid-template-columns: 1fr auto;
     grid-template-columns: 1fr auto;
     align-items: center;
     align-items: center;

+ 5 - 1
packages/atlas/src/components/_auth/SignInModal/SignInModal.tsx

@@ -8,6 +8,7 @@ import { Button } from '@/components/_buttons/Button'
 import { DialogButtonProps } from '@/components/_overlays/Dialog'
 import { DialogButtonProps } from '@/components/_overlays/Dialog'
 import { atlasConfig } from '@/config'
 import { atlasConfig } from '@/config'
 import { FAUCET_URL } from '@/config/env'
 import { FAUCET_URL } from '@/config/env'
+import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics'
 import { MemberId } from '@/joystream-lib/types'
 import { MemberId } from '@/joystream-lib/types'
 import { hapiBnToTokenNumber } from '@/joystream-lib/utils'
 import { hapiBnToTokenNumber } from '@/joystream-lib/utils'
 import { useJoystream } from '@/providers/joystream/joystream.hooks'
 import { useJoystream } from '@/providers/joystream/joystream.hooks'
@@ -56,6 +57,7 @@ export const SignInModal: FC = () => {
   )
   )
 
 
   const { displaySnackbar } = useSnackbar()
   const { displaySnackbar } = useSnackbar()
+  const { identifyUser } = useSegmentAnalytics()
   const { walletStatus, refetchUserMemberships, setActiveUser, isLoggedIn } = useUser()
   const { walletStatus, refetchUserMemberships, setActiveUser, isLoggedIn } = useUser()
   const { signInModalOpen, setSignInModalOpen } = useUserStore(
   const { signInModalOpen, setSignInModalOpen } = useUserStore(
     (state) => ({ signInModalOpen: state.signInModalOpen, setSignInModalOpen: state.actions.setSignInModalOpen }),
     (state) => ({ signInModalOpen: state.signInModalOpen, setSignInModalOpen: state.actions.setSignInModalOpen }),
@@ -114,6 +116,7 @@ export const SignInModal: FC = () => {
         captchaToken: data.captchaToken,
         captchaToken: data.captchaToken,
       }
       }
       const response = await faucetMutation(body)
       const response = await faucetMutation(body)
+
       return response.data
       return response.data
     },
     },
     [avatarMutation, faucetMutation]
     [avatarMutation, faucetMutation]
@@ -131,6 +134,7 @@ export const SignInModal: FC = () => {
           const lastCreatedMembership = data.memberships[data.memberships.length - 1]
           const lastCreatedMembership = data.memberships[data.memberships.length - 1]
           if (lastCreatedMembership) {
           if (lastCreatedMembership) {
             setActiveUser({ accountId: selectedAddress, memberId: lastCreatedMembership.id, channelId: null })
             setActiveUser({ accountId: selectedAddress, memberId: lastCreatedMembership.id, channelId: null })
+            identifyUser(lastCreatedMembership.id)
             displaySnackbar({
             displaySnackbar({
               title: 'Your membership has been created',
               title: 'Your membership has been created',
               description: 'Browse, watch, create, collect videos across the platform and have fun!',
               description: 'Browse, watch, create, collect videos across the platform and have fun!',
@@ -218,11 +222,11 @@ export const SignInModal: FC = () => {
       displaySnackbar,
       displaySnackbar,
       goToNextStep,
       goToNextStep,
       goToPreviousStep,
       goToPreviousStep,
+      identifyUser,
       joystream,
       joystream,
       refetchUserMemberships,
       refetchUserMemberships,
       selectedAddress,
       selectedAddress,
       setActiveUser,
       setActiveUser,
-      setPreviouslyFailedData,
       setSignInModalOpen,
       setSignInModalOpen,
     ]
     ]
   )
   )

+ 1 - 1
packages/atlas/src/components/_auth/SignInModal/SignInSteps/SignInModalMembershipStep.tsx

@@ -148,7 +148,7 @@ export const SignInModalMembershipStep: FC<SignInModalMembershipStepProps> = ({
                       !!imageInputFile?.blob
                       !!imageInputFile?.blob
                     )
                     )
                   }
                   }
-                  assetUrl={imageInputFile?.url}
+                  assetUrls={imageInputFile?.url ? [imageInputFile.url] : undefined}
                   editable
                   editable
                 />
                 />
                 <ImageCropModal
                 <ImageCropModal

+ 1 - 1
packages/atlas/src/components/_channel/ChannelCard/ChannelCard.tsx

@@ -46,7 +46,7 @@ export const ChannelCard: FC<ChannelCardProps> = ({
   return (
   return (
     <ChannelCardArticle className={className} activeDisabled={activeDisabled}>
     <ChannelCardArticle className={className} activeDisabled={activeDisabled}>
       <ChannelCardAnchor onClick={onClick} to={channel?.id ? absoluteRoutes.viewer.channel(channel.id) : ''}>
       <ChannelCardAnchor onClick={onClick} to={channel?.id ? absoluteRoutes.viewer.channel(channel.id) : ''}>
-        <StyledAvatar loading={loading} assetUrl={channel?.avatarPhoto?.resolvedUrl} />
+        <StyledAvatar loading={loading} assetUrls={channel?.avatarPhoto?.resolvedUrls} />
         <SwitchTransition>
         <SwitchTransition>
           <CSSTransition
           <CSSTransition
             key={loading ? 'placeholder' : 'content'}
             key={loading ? 'placeholder' : 'content'}

+ 2 - 2
packages/atlas/src/components/_channel/ChannelCover/ChannelCover.stories.tsx

@@ -9,7 +9,7 @@ export default {
     editable: { table: { required: false } },
     editable: { table: { required: false } },
   },
   },
   args: {
   args: {
-    assetUrl: 'https://eu-central-1.linodeobjects.com/atlas-assets/channel-posters/2.jpg',
+    assetUrls: ['https://eu-central-1.linodeobjects.com/atlas-assets/channel-posters/2.jpg'],
   },
   },
 } as Meta<ChannelCoverProps>
 } as Meta<ChannelCoverProps>
 
 
@@ -30,5 +30,5 @@ export const Default = Template.bind({})
 
 
 export const WithNoImage = Template.bind({})
 export const WithNoImage = Template.bind({})
 WithNoImage.args = {
 WithNoImage.args = {
-  assetUrl: undefined,
+  assetUrls: undefined,
 }
 }

+ 2 - 1
packages/atlas/src/components/_channel/ChannelCover/ChannelCover.styles.ts

@@ -2,6 +2,7 @@ import styled from '@emotion/styled'
 
 
 import { SvgIllustrativeFileFailed } from '@/assets/icons'
 import { SvgIllustrativeFileFailed } from '@/assets/icons'
 import { SvgBgPattern } from '@/assets/illustrations'
 import { SvgBgPattern } from '@/assets/illustrations'
+import { AssetImage } from '@/components/AssetImage'
 import { Button } from '@/components/_buttons/Button'
 import { Button } from '@/components/_buttons/Button'
 import { cVar, media, sizes, transitions, zIndex } from '@/styles'
 import { cVar, media, sizes, transitions, zIndex } from '@/styles'
 
 
@@ -21,7 +22,7 @@ export const Media = styled.div`
   overflow: hidden;
   overflow: hidden;
 `
 `
 
 
-export const CoverImage = styled.img`
+export const CoverImage = styled(AssetImage)`
   width: 100%;
   width: 100%;
   position: absolute;
   position: absolute;
   top: 0;
   top: 0;

+ 10 - 17
packages/atlas/src/components/_channel/ChannelCover/ChannelCover.tsx

@@ -1,9 +1,7 @@
 import { FC, MouseEvent } from 'react'
 import { FC, MouseEvent } from 'react'
-import { CSSTransition, TransitionGroup } from 'react-transition-group'
 
 
 import { SvgActionImage, SvgActionImageFile } from '@/assets/icons'
 import { SvgActionImage, SvgActionImageFile } from '@/assets/icons'
 import { Text } from '@/components/Text'
 import { Text } from '@/components/Text'
-import { transitions } from '@/styles'
 
 
 import {
 import {
   CoverImage,
   CoverImage,
@@ -19,7 +17,7 @@ import {
 } from './ChannelCover.styles'
 } from './ChannelCover.styles'
 
 
 export type ChannelCoverProps = {
 export type ChannelCoverProps = {
-  assetUrl?: string | null
+  assetUrls?: string[] | null
   hasCoverUploadFailed?: boolean
   hasCoverUploadFailed?: boolean
   editable?: boolean
   editable?: boolean
   disabled?: boolean
   disabled?: boolean
@@ -27,7 +25,7 @@ export type ChannelCoverProps = {
 }
 }
 
 
 export const ChannelCover: FC<ChannelCoverProps> = ({
 export const ChannelCover: FC<ChannelCoverProps> = ({
-  assetUrl,
+  assetUrls,
   hasCoverUploadFailed,
   hasCoverUploadFailed,
   editable,
   editable,
   disabled,
   disabled,
@@ -41,22 +39,17 @@ export const ChannelCover: FC<ChannelCoverProps> = ({
             <EditCoverDesktopOverlay onClick={onCoverEditClick}>
             <EditCoverDesktopOverlay onClick={onCoverEditClick}>
               <SvgActionImage />
               <SvgActionImage />
               <Text as="span" variant="t200-strong" margin={{ top: 1 }} color="colorCoreNeutral100">{`${
               <Text as="span" variant="t200-strong" margin={{ top: 1 }} color="colorCoreNeutral100">{`${
-                assetUrl ? 'Edit ' : 'Add '
+                assetUrls ? 'Edit ' : 'Add '
               } cover image`}</Text>
               } cover image`}</Text>
             </EditCoverDesktopOverlay>
             </EditCoverDesktopOverlay>
             <EditCoverMobileButton icon={<SvgActionImageFile />} onClick={onCoverEditClick} variant="tertiary" />
             <EditCoverMobileButton icon={<SvgActionImageFile />} onClick={onCoverEditClick} variant="tertiary" />
           </EditableControls>
           </EditableControls>
         )}
         )}
         <Media>
         <Media>
-          <TransitionGroup>
-            <CSSTransition
-              key={assetUrl ? 'cover' : 'pattern'}
-              timeout={parseInt(transitions.timings.loading)}
-              classNames={transitions.names.fade}
-            >
-              {assetUrl ? (
-                <CoverImage src={assetUrl} />
-              ) : hasCoverUploadFailed ? (
+          <CoverImage
+            resolvedUrls={assetUrls}
+            imagePlaceholder={
+              hasCoverUploadFailed ? (
                 <FailedUploadContainer>
                 <FailedUploadContainer>
                   <StyledSvgIllustrativeFileFailed />
                   <StyledSvgIllustrativeFileFailed />
                   <Text as="span" variant="t100" color="colorText">
                   <Text as="span" variant="t100" color="colorText">
@@ -65,9 +58,9 @@ export const ChannelCover: FC<ChannelCoverProps> = ({
                 </FailedUploadContainer>
                 </FailedUploadContainer>
               ) : (
               ) : (
                 <StyledBackgroundPattern />
                 <StyledBackgroundPattern />
-              )}
-            </CSSTransition>
-          </TransitionGroup>
+              )
+            }
+          />
         </Media>
         </Media>
       </MediaWrapper>
       </MediaWrapper>
     </CoverWrapper>
     </CoverWrapper>

+ 1 - 1
packages/atlas/src/components/_channel/ChannelLink/ChannelLink.tsx

@@ -70,7 +70,7 @@ export const ChannelLink: FC<ChannelLinkProps> = ({
             withHandle={!hideHandle}
             withHandle={!hideHandle}
             loading={!displayedChannel}
             loading={!displayedChannel}
             size={avatarSize}
             size={avatarSize}
-            assetUrl={displayedChannel?.channel.avatarPhoto?.resolvedUrl}
+            assetUrls={displayedChannel?.channel.avatarPhoto?.resolvedUrls}
           />
           />
         </StyledLink>
         </StyledLink>
       )}
       )}

+ 1 - 1
packages/atlas/src/components/_channel/ChannelWithVideos/ChannelWithVideos.tsx

@@ -77,7 +77,7 @@ export const ChannelWithVideos: FC<ChannelWithVideosProps> = memo(({ channelId }
         <StyledAvatar
         <StyledAvatar
           size={mdMatch ? 136 : 88}
           size={mdMatch ? 136 : 88}
           loading={isLoading}
           loading={isLoading}
-          assetUrl={extendedChannel?.channel.avatarPhoto?.resolvedUrl}
+          assetUrls={extendedChannel?.channel.avatarPhoto?.resolvedUrls}
         />
         />
         <InfoWrapper>
         <InfoWrapper>
           {isLoading ? (
           {isLoading ? (

+ 4 - 4
packages/atlas/src/components/_channel/CollectorsBox/CollectorsBox.stories.tsx

@@ -45,19 +45,19 @@ export const Default = Template.bind({})
 export const WithLessThan5Collectors = Template.bind({})
 export const WithLessThan5Collectors = Template.bind({})
 WithLessThan5Collectors.args = {
 WithLessThan5Collectors.args = {
   collectors: [
   collectors: [
-    { url: 'https://thispersondoesnotexist.com/image', tooltipText: 'William', nftsAmount: 6 },
+    { urls: ['https://thispersondoesnotexist.com/image'], tooltipText: 'William', nftsAmount: 6 },
     {
     {
-      url: 'https://eu-central-1.linodeobjects.com/atlas-assets/channel-posters/2.jpg',
+      urls: ['https://eu-central-1.linodeobjects.com/atlas-assets/channel-posters/2.jpg'],
       tooltipText: 'Someone',
       tooltipText: 'Someone',
       nftsAmount: 1,
       nftsAmount: 1,
     },
     },
-    { url: 'https://thispersondoesnotexist.com/image', tooltipText: 'Someone else', nftsAmount: 7 },
+    { urls: ['https://thispersondoesnotexist.com/image'], tooltipText: 'Someone else', nftsAmount: 7 },
   ],
   ],
 }
 }
 
 
 const TemplateWithChannelCover: StoryFn<CollectorsBoxProps> = (args) => (
 const TemplateWithChannelCover: StoryFn<CollectorsBoxProps> = (args) => (
   <div style={{ position: 'relative' }}>
   <div style={{ position: 'relative' }}>
-    <ChannelCover assetUrl="https://eu-central-1.linodeobjects.com/atlas-assets/channel-posters/2.jpg" />
+    <ChannelCover assetUrls={['https://eu-central-1.linodeobjects.com/atlas-assets/channel-posters/2.jpg']} />
     <div style={{ position: 'absolute', bottom: -32, right: 0 }}>
     <div style={{ position: 'absolute', bottom: -32, right: 0 }}>
       <CollectorsBox {...args} />
       <CollectorsBox {...args} />
     </div>
     </div>

+ 1 - 1
packages/atlas/src/components/_channel/CollectorsBox/CollectorsBox.tsx

@@ -67,7 +67,7 @@ export const CollectorsBox: FC<CollectorsBoxProps> = ({ collectors, maxShowedCol
         {mappedCollectors.map((collector, idx) => (
         {mappedCollectors.map((collector, idx) => (
           <StyledLink key={idx} to={collector.memberUrl || ''}>
           <StyledLink key={idx} to={collector.memberUrl || ''}>
             <ListItem
             <ListItem
-              nodeStart={<Avatar size={40} assetUrl={collector.url} />}
+              nodeStart={<Avatar size={40} assetUrls={collector.urls} />}
               nodeEnd={
               nodeEnd={
                 <Text as="span" variant="t100" color="colorText">
                 <Text as="span" variant="t100" color="colorText">
                   Owns {collector.nftsAmount}
                   Owns {collector.nftsAmount}

+ 3 - 3
packages/atlas/src/components/_comments/Comment/Comment.tsx

@@ -65,7 +65,7 @@ export const Comment: FC<CommentProps> = memo(
         skip: !commentId,
         skip: !commentId,
       }
       }
     )
     )
-    const { isLoadingAsset: isMemberAvatarLoading, url: memberAvatarUrl } = getMemberAvatar(activeMembership)
+    const { isLoadingAsset: isMemberAvatarLoading, urls: memberAvatarUrls } = getMemberAvatar(activeMembership)
 
 
     const commentIdQueryParam = useRouterQuery(QUERY_PARAMS.COMMENT_ID)
     const commentIdQueryParam = useRouterQuery(QUERY_PARAMS.COMMENT_ID)
     const reactionPopoverDismissed = usePersonalDataStore((state) => state.reactionPopoverDismissed)
     const reactionPopoverDismissed = usePersonalDataStore((state) => state.reactionPopoverDismissed)
@@ -280,7 +280,7 @@ export const Comment: FC<CommentProps> = memo(
           processing={editCommentInputIsProcessing}
           processing={editCommentInputIsProcessing}
           readOnly={!memberId}
           readOnly={!memberId}
           memberHandle={activeMembership?.handle}
           memberHandle={activeMembership?.handle}
-          memberAvatarUrl={memberAvatarUrl}
+          memberAvatarUrls={memberAvatarUrls}
           isMemberAvatarLoading={isMemberAvatarLoading}
           isMemberAvatarLoading={isMemberAvatarLoading}
           value={editCommentInputText}
           value={editCommentInputText}
           hasInitialValueChanged={comment?.text !== editCommentInputText}
           hasInitialValueChanged={comment?.text !== editCommentInputText}
@@ -334,7 +334,7 @@ export const Comment: FC<CommentProps> = memo(
               ref={replyCommentInputRef}
               ref={replyCommentInputRef}
               fee={replyCommentFee}
               fee={replyCommentFee}
               feeLoading={replyCommentFeeLoading}
               feeLoading={replyCommentFeeLoading}
-              memberAvatarUrl={memberAvatarUrl}
+              memberAvatarUrls={memberAvatarUrls}
               isMemberAvatarLoading={isMemberAvatarLoading}
               isMemberAvatarLoading={isMemberAvatarLoading}
               processing={replyCommentInputIsProcessing}
               processing={replyCommentInputIsProcessing}
               readOnly={!memberId}
               readOnly={!memberId}

+ 3 - 3
packages/atlas/src/components/_comments/Comment/InternalComment.tsx

@@ -115,11 +115,11 @@ export const InternalComment: FC<InternalCommentProps> = ({
 
 
   const popoverRef = useRef<PopoverImperativeHandle>(null)
   const popoverRef = useRef<PopoverImperativeHandle>(null)
   const isTouchDevice = useTouchDevice()
   const isTouchDevice = useTouchDevice()
-  const { url: memberAvatarUrl, isLoadingAsset: isMemberAvatarLoading } = getMemberAvatar(author)
+  const { urls: memberAvatarUrls, isLoadingAsset: isMemberAvatarLoading } = getMemberAvatar(author)
   const filteredDuplicatedAvatars = repliesCount
   const filteredDuplicatedAvatars = repliesCount
     ? replyAvatars
     ? replyAvatars
       ? [...new Map(replyAvatars?.map((item) => [item.handle, item])).values()]
       ? [...new Map(replyAvatars?.map((item) => [item.handle, item])).values()]
-      : createPlaceholderData(repliesCount, { url: undefined })
+      : createPlaceholderData(repliesCount, { urls: undefined })
     : []
     : []
 
 
   const tooltipDate = createdAt ? `${formatDate(createdAt || new Date())} at ${format(createdAt, 'HH:mm')}` : undefined
   const tooltipDate = createdAt ? `${formatDate(createdAt || new Date())} at ${format(createdAt, 'HH:mm')}` : undefined
@@ -185,7 +185,7 @@ export const InternalComment: FC<InternalCommentProps> = ({
       highlighted={highlighted}
       highlighted={highlighted}
       isMemberAvatarLoading={loading || isMemberAvatarLoading}
       isMemberAvatarLoading={loading || isMemberAvatarLoading}
       memberUrl={memberUrl}
       memberUrl={memberUrl}
-      memberAvatarUrl={memberAvatarUrl}
+      memberAvatarUrls={memberAvatarUrls}
       onMouseEnter={() => setCommentHover(true)}
       onMouseEnter={() => setCommentHover(true)}
       onMouseLeave={() => setCommentHover(false)}
       onMouseLeave={() => setCommentHover(false)}
     >
     >

+ 2 - 2
packages/atlas/src/components/_comments/CommentEditHistory/CommentEditHistory.tsx

@@ -18,7 +18,7 @@ type CommentEditHistoryProps = {
 
 
 export const CommentEditHistory: FC<CommentEditHistoryProps> = ({ originalComment }) => {
 export const CommentEditHistory: FC<CommentEditHistoryProps> = ({ originalComment }) => {
   const { commentEdits, loading } = useCommentEdits(originalComment?.id)
   const { commentEdits, loading } = useCommentEdits(originalComment?.id)
-  const { url: memberAvatarUrl, isLoadingAsset } = getMemberAvatar(originalComment?.author)
+  const { urls: memberAvatarUrls, isLoadingAsset } = getMemberAvatar(originalComment?.author)
 
 
   const placeholderItems = createPlaceholderData(3)
   const placeholderItems = createPlaceholderData(3)
 
 
@@ -47,7 +47,7 @@ export const CommentEditHistory: FC<CommentEditHistoryProps> = ({ originalCommen
                   memberUrl={absoluteRoutes.viewer.member(originalComment?.author?.handle)}
                   memberUrl={absoluteRoutes.viewer.member(originalComment?.author?.handle)}
                   text={commentEdit.data.text}
                   text={commentEdit.data.text}
                   loading={loading}
                   loading={loading}
-                  memberAvatarUrl={memberAvatarUrl || ''}
+                  memberAvatarUrls={memberAvatarUrls}
                   isMemberAvatarLoading={isLoadingAsset}
                   isMemberAvatarLoading={isLoadingAsset}
                 />
                 />
               )
               )

+ 4 - 4
packages/atlas/src/components/_comments/CommentRow/CommentRow.tsx

@@ -11,7 +11,7 @@ export type CommentRowProps = PropsWithChildren<{
   processing?: boolean
   processing?: boolean
   highlighted?: boolean
   highlighted?: boolean
   isMemberAvatarLoading?: boolean
   isMemberAvatarLoading?: boolean
-  memberAvatarUrl?: string | null
+  memberAvatarUrls?: string[] | null
   memberUrl?: string
   memberUrl?: string
   className?: string
   className?: string
   isInput?: boolean
   isInput?: boolean
@@ -24,7 +24,7 @@ export const CommentRow: FC<CommentRowProps> = ({
   processing,
   processing,
   highlighted,
   highlighted,
   children,
   children,
-  memberAvatarUrl,
+  memberAvatarUrls,
   isMemberAvatarLoading,
   isMemberAvatarLoading,
   memberUrl = '',
   memberUrl = '',
   className,
   className,
@@ -61,10 +61,10 @@ export const CommentRow: FC<CommentRowProps> = ({
         <div>
         <div>
           {memberUrl ? (
           {memberUrl ? (
             <Link to={memberUrl}>
             <Link to={memberUrl}>
-              <Avatar assetUrl={memberAvatarUrl} size={avatarSize} loading={isMemberAvatarLoading} clickable />
+              <Avatar assetUrls={memberAvatarUrls} size={avatarSize} loading={isMemberAvatarLoading} clickable />
             </Link>
             </Link>
           ) : (
           ) : (
-            <Avatar assetUrl={memberAvatarUrl} size={avatarSize} loading={isMemberAvatarLoading} />
+            <Avatar assetUrls={memberAvatarUrls} size={avatarSize} loading={isMemberAvatarLoading} />
           )}
           )}
         </div>
         </div>
         <div className={className}>{children}</div>
         <div className={className}>{children}</div>

+ 3 - 3
packages/atlas/src/components/_comments/CommentSnapshot/CommentSnaphsot.tsx

@@ -21,7 +21,7 @@ import { CommentBody } from '../CommentBody'
 
 
 export type CommentSnapshotProps = {
 export type CommentSnapshotProps = {
   isMemberAvatarLoading?: boolean
   isMemberAvatarLoading?: boolean
-  memberAvatarUrl?: string
+  memberAvatarUrls?: string[] | null
   memberUrl?: string
   memberUrl?: string
   memberHandle?: string
   memberHandle?: string
   loading?: boolean
   loading?: boolean
@@ -31,7 +31,7 @@ export type CommentSnapshotProps = {
 }
 }
 
 
 export const CommentSnapshot: FC<CommentSnapshotProps> = ({
 export const CommentSnapshot: FC<CommentSnapshotProps> = ({
-  memberAvatarUrl,
+  memberAvatarUrls,
   isMemberAvatarLoading,
   isMemberAvatarLoading,
   memberHandle,
   memberHandle,
   loading,
   loading,
@@ -44,7 +44,7 @@ export const CommentSnapshot: FC<CommentSnapshotProps> = ({
     <ContentWrapper>
     <ContentWrapper>
       <AvatarWrapper>
       <AvatarWrapper>
         <Link to={memberUrl}>
         <Link to={memberUrl}>
-          <Avatar assetUrl={memberAvatarUrl} size={40} loading={isMemberAvatarLoading} clickable />
+          <Avatar assetUrls={memberAvatarUrls} size={40} loading={isMemberAvatarLoading} clickable />
         </Link>
         </Link>
         {!last && <Line />}
         {!last && <Line />}
       </AvatarWrapper>
       </AvatarWrapper>

+ 18 - 18
packages/atlas/src/components/_inputs/ComboBox/ComboBox.stories.tsx

@@ -13,77 +13,77 @@ const MEMBERS = [
   {
   {
     id: 1,
     id: 1,
     label: 'Klaudiusz',
     label: 'Klaudiusz',
-    thumbnailUrl: 'https://placedog.net/57/32?random=1',
+    thumbnailUrls: ['https://placedog.net/57/32?random=1'],
   },
   },
   {
   {
     id: 2,
     id: 2,
     label: 'Diego',
     label: 'Diego',
-    thumbnailUrl: 'https://placedog.net/57/32?random=2',
+    thumbnailUrls: ['https://placedog.net/57/32?random=2'],
   },
   },
   {
   {
     id: 3,
     id: 3,
     label: 'Rafal',
     label: 'Rafal',
-    thumbnailUrl: 'https://placedog.net/57/32?random=3',
+    thumbnailUrls: ['https://placedog.net/57/32?random=3'],
   },
   },
   {
   {
     id: 3,
     id: 3,
     label: 'Loic',
     label: 'Loic',
-    thumbnailUrl: 'https://placedog.net/57/32?random=4',
+    thumbnailUrls: ['https://placedog.net/57/32?random=4'],
   },
   },
   {
   {
     id: 4,
     id: 4,
     label: 'Bartosz',
     label: 'Bartosz',
-    thumbnailUrl: 'https://placedog.net/57/32?random=5',
+    thumbnailUrls: ['https://placedog.net/57/32?random=5'],
   },
   },
   {
   {
     id: 5,
     id: 5,
     label: 'Klaudiusz the Second',
     label: 'Klaudiusz the Second',
-    thumbnailUrl: 'https://placedog.net/57/32?random=6',
+    thumbnailUrls: ['https://placedog.net/57/32?random=6'],
   },
   },
   {
   {
     id: 6,
     id: 6,
     label: 'Diego the Second',
     label: 'Diego the Second',
-    thumbnailUrl: 'https://placedog.net/57/32?random=7',
+    thumbnailUrls: ['https://placedog.net/57/32?random=7'],
   },
   },
   {
   {
     id: 7,
     id: 7,
     label: 'Rafal the Second',
     label: 'Rafal the Second',
-    thumbnailUrl: 'https://placedog.net/57/32?random=8',
+    thumbnailUrls: ['https://placedog.net/57/32?random=8'],
   },
   },
   {
   {
     id: 8,
     id: 8,
     label: 'Loic the Second',
     label: 'Loic the Second',
-    thumbnailUrl: 'https://placedog.net/57/32?random=9',
+    thumbnailUrls: ['https://placedog.net/57/32?random=9'],
   },
   },
   {
   {
     id: 9,
     id: 9,
     label: 'Bartosz the Second',
     label: 'Bartosz the Second',
-    thumbnailUrl: 'https://placedog.net/57/32?random=10',
+    thumbnailUrls: ['https://placedog.net/57/32?random=10'],
   },
   },
   {
   {
     id: 10,
     id: 10,
     label: 'Klaudiusz the Third',
     label: 'Klaudiusz the Third',
-    thumbnailUrl: 'https://placedog.net/57/32?random=11',
+    thumbnailUrls: ['https://placedog.net/57/32?random=11'],
   },
   },
   {
   {
     id: 11,
     id: 11,
     label: 'Diego the Third',
     label: 'Diego the Third',
-    thumbnailUrl: 'https://placedog.net/57/32?random=12',
+    thumbnailUrls: ['https://placedog.net/57/32?random=12'],
   },
   },
   {
   {
     id: 12,
     id: 12,
     label: 'Rafal the Third',
     label: 'Rafal the Third',
-    thumbnailUrl: 'https://placedog.net/57/32?random=13',
+    thumbnailUrls: ['https://placedog.net/57/32?random=13'],
   },
   },
   {
   {
     id: 13,
     id: 13,
     label: 'Loic the Third',
     label: 'Loic the Third',
-    thumbnailUrl: 'https://placedog.net/57/32?random=14',
+    thumbnailUrls: ['https://placedog.net/57/32?random=14'],
   },
   },
   {
   {
     id: 14,
     id: 14,
     label: 'Bartosz the Third',
     label: 'Bartosz the Third',
-    thumbnailUrl: 'https://placedog.net/57/32?random=15',
+    thumbnailUrls: ['https://placedog.net/57/32?random=15'],
   },
   },
 ]
 ]
 
 
@@ -134,7 +134,7 @@ const Template: StoryFn<ComboBoxProps> = (args) => {
 
 
 export const Default = Template.bind({})
 export const Default = Template.bind({})
 
 
-type Member = { label: string; thumbnailUrl: string; id: string }
+type Member = { label: string; thumbnailUrls: string[]; id: string }
 const TemplateWithMembers: StoryFn<ComboBoxProps> = (args) => {
 const TemplateWithMembers: StoryFn<ComboBoxProps> = (args) => {
   const [selectedMembers, setSelectedMembers] = useState<Member[]>([])
   const [selectedMembers, setSelectedMembers] = useState<Member[]>([])
   const [focusedElement, setFocusedElement] = useState<number | null>(null)
   const [focusedElement, setFocusedElement] = useState<number | null>(null)
@@ -167,7 +167,7 @@ const TemplateWithMembers: StoryFn<ComboBoxProps> = (args) => {
         items={dropdownItems.map((member) => ({
         items={dropdownItems.map((member) => ({
           id: member.id,
           id: member.id,
           label: member.label,
           label: member.label,
-          thumbnailUrl: '',
+          thumbnailUrls: [],
         }))}
         }))}
         resetOnSelect
         resetOnSelect
       />
       />
@@ -175,7 +175,7 @@ const TemplateWithMembers: StoryFn<ComboBoxProps> = (args) => {
         {selectedMembers.map((member, idx) => (
         {selectedMembers.map((member, idx) => (
           <OutputPill
           <OutputPill
             withAvatar
             withAvatar
-            avatarUri={member.thumbnailUrl}
+            avatarUrls={member.thumbnailUrls}
             key={member.id}
             key={member.id}
             handle={member.label}
             handle={member.label}
             onDeleteClick={() => handleDeleteMember(member.id)}
             onDeleteClick={() => handleDeleteMember(member.id)}

+ 2 - 1
packages/atlas/src/components/_inputs/ComboBox/ComboBox.styles.ts

@@ -1,6 +1,7 @@
 import styled from '@emotion/styled'
 import styled from '@emotion/styled'
 
 
 import { SvgActionPlus } from '@/assets/icons'
 import { SvgActionPlus } from '@/assets/icons'
+import { AssetImage } from '@/components/AssetImage'
 import { cVar, sizes, zIndex } from '@/styles'
 import { cVar, sizes, zIndex } from '@/styles'
 
 
 export const ComboBoxWrapper = styled.div`
 export const ComboBoxWrapper = styled.div`
@@ -19,7 +20,7 @@ export const ListWrapper = styled.ul<{ isOpen: boolean }>`
   margin: 0;
   margin: 0;
 `
 `
 
 
-export const StyledThumbnail = styled.img`
+export const StyledThumbnail = styled(AssetImage)`
   max-height: 32px;
   max-height: 32px;
 `
 `
 
 

+ 4 - 2
packages/atlas/src/components/_inputs/ComboBox/ComboBox.tsx

@@ -14,7 +14,7 @@ import { Input, InputProps } from '../Input'
 
 
 type ModifiedListItemProps = ListItemProps & {
 type ModifiedListItemProps = ListItemProps & {
   label: string
   label: string
-  thumbnailUrl?: string
+  thumbnailUrls?: string[]
   isSeparator?: boolean
   isSeparator?: boolean
 }
 }
 
 
@@ -134,7 +134,9 @@ export const ComboBox = <T extends unknown>(props: ComboBoxProps<T>) => {
                     })}
                     })}
                     size="large"
                     size="large"
                     highlight={highlightedIndex === index}
                     highlight={highlightedIndex === index}
-                    nodeStart={item.nodeStart || (item.thumbnailUrl && <StyledThumbnail src={item.thumbnailUrl} />)}
+                    nodeStart={
+                      item.nodeStart || (item.thumbnailUrls && <StyledThumbnail resolvedUrls={item.thumbnailUrls} />)
+                    }
                     isSeparator={item.isSeparator}
                     isSeparator={item.isSeparator}
                   />
                   />
                 ))}
                 ))}

+ 1 - 1
packages/atlas/src/components/_inputs/Input/Input.stories.tsx

@@ -60,7 +60,7 @@ const TemplateWithPreffixAndSuffix: StoryFn<InputProps> = (args) => {
       <Input {...args} nodeStart={<Pill label="label" />} nodeEnd="$" />
       <Input {...args} nodeStart={<Pill label="label" />} nodeEnd="$" />
       <Input
       <Input
         {...args}
         {...args}
-        nodeStart={<Avatar size={24} assetUrl="https://placedog.net/360/203" />}
+        nodeStart={<Avatar size={24} assetUrls={['https://placedog.net/360/203']} />}
         nodeEnd={<Pill label="500$" />}
         nodeEnd={<Pill label="500$" />}
       />
       />
       <Input
       <Input

+ 4 - 4
packages/atlas/src/components/_inputs/MemberComboBox/MemberComboBox.tsx

@@ -137,8 +137,8 @@ type AvatarWithResolvedAssetProps = {
 }
 }
 
 
 const AvatarWithResolvedAsset: FC<AvatarWithResolvedAssetProps> = ({ member }) => {
 const AvatarWithResolvedAsset: FC<AvatarWithResolvedAssetProps> = ({ member }) => {
-  const { url, isLoadingAsset } = getMemberAvatar(member)
-  return <Avatar size={32} assetUrl={url} loading={isLoadingAsset} />
+  const { urls, isLoadingAsset } = getMemberAvatar(member)
+  return <Avatar size={32} assetUrls={urls} loading={isLoadingAsset} />
 }
 }
 
 
 type StyledOutputPillWithResolvedAssetProps = {
 type StyledOutputPillWithResolvedAssetProps = {
@@ -154,12 +154,12 @@ const StyledOutputPillWithResolvedAsset: FC<StyledOutputPillWithResolvedAssetPro
   onKeyPress,
   onKeyPress,
   focused,
   focused,
 }) => {
 }) => {
-  const { url, isLoadingAsset } = getMemberAvatar(member)
+  const { urls, isLoadingAsset } = getMemberAvatar(member)
   return (
   return (
     <StyledOutputPill
     <StyledOutputPill
       handle={member.handle}
       handle={member.handle}
       onDeleteClick={onDeleteClick}
       onDeleteClick={onDeleteClick}
-      avatarUri={url}
+      avatarUrls={urls}
       isLoadingAvatar={isLoadingAsset}
       isLoadingAvatar={isLoadingAsset}
       withAvatar
       withAvatar
       onKeyPress={onKeyPress}
       onKeyPress={onKeyPress}

+ 2 - 2
packages/atlas/src/components/_inputs/SubtitlesBox/SubtitlesBox.tsx

@@ -8,6 +8,7 @@ import { Text } from '@/components/Text'
 import { Button } from '@/components/_buttons/Button'
 import { Button } from '@/components/_buttons/Button'
 import { ContextMenu } from '@/components/_overlays/ContextMenu'
 import { ContextMenu } from '@/components/_overlays/ContextMenu'
 import { atlasConfig } from '@/config'
 import { atlasConfig } from '@/config'
+import { useGetAssetUrl } from '@/hooks/useGetAssetUrl'
 import { useConfirmationModal } from '@/providers/confirmationModal'
 import { useConfirmationModal } from '@/providers/confirmationModal'
 import { SubtitlesInput } from '@/types/subtitles'
 import { SubtitlesInput } from '@/types/subtitles'
 
 
@@ -42,8 +43,7 @@ export const SubtitlesBox: FC<SubtitleBoxProps> = ({
   const { mutateAsync: subtitlesFetch } = useMutation('subtitles-fetch', (url: string) =>
   const { mutateAsync: subtitlesFetch } = useMutation('subtitles-fetch', (url: string) =>
     axios.get(url, { responseType: 'blob' })
     axios.get(url, { responseType: 'blob' })
   )
   )
-
-  const url = asset?.resolvedUrl
+  const { url } = useGetAssetUrl(asset?.resolvedUrls, 'subtitle')
 
 
   const handleDownload = async (url = '') => {
   const handleDownload = async (url = '') => {
     const response = await subtitlesFetch(url)
     const response = await subtitlesFetch(url)

+ 1 - 1
packages/atlas/src/components/_navigation/SidenavViewer/FollowedChannels.tsx

@@ -44,7 +44,7 @@ export const ChannelNavItem: FC<NavItemProps & ChannelNavItemProps> = ({
 
 
   return (
   return (
     <NavItem to={to} expanded={expanded} itemName={itemName} onClick={onClick} isSecondary={isSecondary}>
     <NavItem to={to} expanded={expanded} itemName={itemName} onClick={onClick} isSecondary={isSecondary}>
-      <Avatar loading={!extendedChannel} size={32} assetUrl={extendedChannel?.channel.avatarPhoto?.resolvedUrl} />
+      <Avatar loading={!extendedChannel} size={32} assetUrls={extendedChannel?.channel.avatarPhoto?.resolvedUrls} />
       {extendedChannel ? (
       {extendedChannel ? (
         <ChannelTitle as="p" variant="h300" color="colorText">
         <ChannelTitle as="p" variant="h300" color="colorText">
           {extendedChannel.channel.title}
           {extendedChannel.channel.title}

+ 5 - 5
packages/atlas/src/components/_navigation/TopbarStudio/TopbarStudio.tsx

@@ -31,9 +31,9 @@ export const TopbarStudio: FC<StudioTopbarProps> = ({ hideChannelInfo, isMembers
 
 
   const currentChannel = activeMembership?.channels.find((channel) => channel.id === channelId)
   const currentChannel = activeMembership?.channels.find((channel) => channel.id === channelId)
 
 
-  const channelAvatarUrl = currentChannel?.avatarPhoto?.resolvedUrl
+  const channelAvatarUrls = currentChannel?.avatarPhoto?.resolvedUrls
 
 
-  const { url: memberAvatarUrl, isLoadingAsset: memberAvatarLoading } = getMemberAvatar(activeMembership)
+  const { urls: memberAvatarUrls, isLoadingAsset: memberAvatarLoading } = getMemberAvatar(activeMembership)
 
 
   const [isMemberDropdownActive, setIsMemberDropdownActive] = useState(false)
   const [isMemberDropdownActive, setIsMemberDropdownActive] = useState(false)
 
 
@@ -53,13 +53,13 @@ export const TopbarStudio: FC<StudioTopbarProps> = ({ hideChannelInfo, isMembers
   const avatars: AvatarGroupUrlAvatar[] = channelId
   const avatars: AvatarGroupUrlAvatar[] = channelId
     ? [
     ? [
         {
         {
-          url: memberAvatarUrl,
+          urls: memberAvatarUrls,
           loading: memberAvatarLoading,
           loading: memberAvatarLoading,
           onClick: handleDrawerToggle,
           onClick: handleDrawerToggle,
         },
         },
-        { url: channelAvatarUrl, loading: isAuthLoading, onClick: handleDrawerToggle },
+        { urls: channelAvatarUrls, loading: isAuthLoading, onClick: handleDrawerToggle },
       ]
       ]
-    : [{ url: memberAvatarUrl, loading: memberAvatarLoading, onClick: handleDrawerToggle }]
+    : [{ urls: memberAvatarUrls, loading: memberAvatarLoading, onClick: handleDrawerToggle }]
 
 
   return (
   return (
     <>
     <>

+ 3 - 3
packages/atlas/src/components/_navigation/TopbarViewer/TopbarViewer.tsx

@@ -33,7 +33,7 @@ export const TopbarViewer: FC = () => {
   const { isLoggedIn, activeMembership, signIn, isAuthLoading } = useUser()
   const { isLoggedIn, activeMembership, signIn, isAuthLoading } = useUser()
   const [isMemberDropdownActive, setIsMemberDropdownActive] = useState(false)
   const [isMemberDropdownActive, setIsMemberDropdownActive] = useState(false)
 
 
-  const { url: memberAvatarUrl, isLoadingAsset: memberAvatarLoading } = getMemberAvatar(activeMembership)
+  const { urls: memberAvatarUrls, isLoadingAsset: memberAvatarLoading } = getMemberAvatar(activeMembership)
 
 
   const { pathname, search } = useLocation()
   const { pathname, search } = useLocation()
   const mdMatch = useMediaMatch('md')
   const mdMatch = useMediaMatch('md')
@@ -126,7 +126,7 @@ export const TopbarViewer: FC = () => {
                       {!mdMatch && !searchOpen && (
                       {!mdMatch && !searchOpen && (
                         <StyledAvatar
                         <StyledAvatar
                           size={40}
                           size={40}
-                          assetUrl={memberAvatarUrl}
+                          assetUrls={memberAvatarUrls}
                           loading={memberAvatarLoading}
                           loading={memberAvatarLoading}
                           onClick={handleDrawerToggle}
                           onClick={handleDrawerToggle}
                         />
                         />
@@ -134,7 +134,7 @@ export const TopbarViewer: FC = () => {
                       {mdMatch && (
                       {mdMatch && (
                         <StyledAvatar
                         <StyledAvatar
                           size={40}
                           size={40}
-                          assetUrl={memberAvatarUrl}
+                          assetUrls={memberAvatarUrls}
                           onClick={handleDrawerToggle}
                           onClick={handleDrawerToggle}
                           loading={memberAvatarLoading}
                           loading={memberAvatarLoading}
                         />
                         />

+ 3 - 3
packages/atlas/src/components/_nft/NftCard/Members.tsx

@@ -15,7 +15,7 @@ import {
 } from './NftCard.styles'
 } from './NftCard.styles'
 
 
 export type Member = {
 export type Member = {
-  assetUrl?: string | null
+  assetUrls?: string[] | null
   name?: string | null
   name?: string | null
 }
 }
 
 
@@ -30,7 +30,7 @@ type MembersProps =
 export const Members: FC<MembersProps> = ({ caption, members, loading }) => {
 export const Members: FC<MembersProps> = ({ caption, members, loading }) => {
   const avatars =
   const avatars =
     members && Array.isArray(members)
     members && Array.isArray(members)
-      ? members.map((member) => ({ assetUrl: member.assetUrl, ...(member.name ? { tooltipText: member.name } : {}) }))
+      ? members.map((member) => ({ assetUrls: member.assetUrls, ...(member.name ? { tooltipText: member.name } : {}) }))
       : null
       : null
   const isArray = Array.isArray(members)
   const isArray = Array.isArray(members)
   return (
   return (
@@ -53,7 +53,7 @@ export const Members: FC<MembersProps> = ({ caption, members, loading }) => {
       )}
       )}
       {!isArray && (
       {!isArray && (
         <AvatarWrapper>
         <AvatarWrapper>
-          <StyledAvatar size={24} assetUrl={members.assetUrl} loading={loading} />
+          <StyledAvatar size={24} assetUrls={members.assetUrls} loading={loading} />
           {loading ? (
           {loading ? (
             <SkeletonLoader width={64} height={24} />
             <SkeletonLoader width={64} height={24} />
           ) : (
           ) : (

+ 1 - 0
packages/atlas/src/components/_nft/NftTile/NftTile.styles.ts

@@ -6,4 +6,5 @@ type ContainerProps = {
 
 
 export const Container = styled.div<ContainerProps>`
 export const Container = styled.div<ContainerProps>`
   width: ${({ fullWidth }) => (fullWidth ? '100%' : '320px')};
   width: ${({ fullWidth }) => (fullWidth ? '100%' : '320px')};
+  overflow: hidden;
 `
 `

+ 2 - 1
packages/atlas/src/components/_nft/NftTile/NftTile.tsx

@@ -76,10 +76,11 @@ export const NftTile: FC<NftTileProps> = ({
       <VideoThumbnail
       <VideoThumbnail
         type="video"
         type="video"
         videoHref={thumbnail?.videoHref}
         videoHref={thumbnail?.videoHref}
+        linkState={{ shouldCollapse: false }}
         onMouseEnter={() => setHovered(true)}
         onMouseEnter={() => setHovered(true)}
         onMouseLeave={() => setHovered(false)}
         onMouseLeave={() => setHovered(false)}
         loading={loading}
         loading={loading}
-        thumbnailUrl={thumbnail?.thumbnailUrl}
+        thumbnailUrls={thumbnail?.thumbnailUrls}
         clickable={false}
         clickable={false}
         slots={{
         slots={{
           topLeft: views
           topLeft: views

+ 1 - 0
packages/atlas/src/components/_nft/NftTile/NftTileDetails.styles.ts

@@ -62,6 +62,7 @@ const tileSizeVariants = ({ tileSize }: ContentProps) => css`
 const isContentPropValid = (prop: string) => prop !== 'loading' && prop !== 'tileSize' && prop !== 'shouldHover'
 const isContentPropValid = (prop: string) => prop !== 'loading' && prop !== 'tileSize' && prop !== 'shouldHover'
 export const Content = styled(Link, { shouldForwardProp: isContentPropValid })<ContentProps>`
 export const Content = styled(Link, { shouldForwardProp: isContentPropValid })<ContentProps>`
   display: block;
   display: block;
+  height: 100%;
   text-decoration: none;
   text-decoration: none;
   background-color: ${cVar('colorBackgroundMuted')};
   background-color: ${cVar('colorBackgroundMuted')};
   transition: background-color ${cVar('animationTransitionFast')};
   transition: background-color ${cVar('animationTransitionFast')};

+ 14 - 6
packages/atlas/src/components/_nft/NftTile/NftTileDetails.tsx

@@ -24,7 +24,7 @@ import {
 } from './NftTileDetails.styles'
 } from './NftTileDetails.styles'
 
 
 export type Member = {
 export type Member = {
-  assetUrl?: string | null
+  assetUrls?: string[] | null
   name?: string
   name?: string
   onClick?: () => void
   onClick?: () => void
   loading?: boolean
   loading?: boolean
@@ -118,6 +118,7 @@ export const NftTileDetails: FC<NftTileDetailsProps> = memo(
               content="Not for sale"
               content="Not for sale"
               icon={<SvgActionNotForSale />}
               icon={<SvgActionNotForSale />}
               secondary
               secondary
+              withDenomination
             />
             />
           )
           )
         case 'buy-now':
         case 'buy-now':
@@ -127,6 +128,7 @@ export const NftTileDetails: FC<NftTileDetailsProps> = memo(
               caption="Buy now"
               caption="Buy now"
               content={buyNowPrice ?? 0}
               content={buyNowPrice ?? 0}
               icon={<JoyTokenIcon size={16} variant="regular" />}
               icon={<JoyTokenIcon size={16} variant="regular" />}
+              withDenomination
             />
             />
           )
           )
         case 'auction':
         case 'auction':
@@ -138,6 +140,7 @@ export const NftTileDetails: FC<NftTileDetailsProps> = memo(
                   caption="Top bid"
                   caption="Top bid"
                   content={topBid}
                   content={topBid}
                   icon={<JoyTokenIcon size={16} variant="regular" />}
                   icon={<JoyTokenIcon size={16} variant="regular" />}
+                  withDenomination
                 />
                 />
               ) : (
               ) : (
                 <DetailsContent
                 <DetailsContent
@@ -145,6 +148,7 @@ export const NftTileDetails: FC<NftTileDetailsProps> = memo(
                   caption="Min bid"
                   caption="Min bid"
                   content={startingPrice ?? 0}
                   content={startingPrice ?? 0}
                   icon={<JoyTokenIcon size={16} variant="regular" />}
                   icon={<JoyTokenIcon size={16} variant="regular" />}
+                  withDenomination
                 />
                 />
               )}
               )}
               {!!buyNowPrice && (
               {!!buyNowPrice && (
@@ -153,6 +157,7 @@ export const NftTileDetails: FC<NftTileDetailsProps> = memo(
                   caption="Buy now"
                   caption="Buy now"
                   content={buyNowPrice}
                   content={buyNowPrice}
                   icon={<JoyTokenIcon size={16} variant="regular" />}
                   icon={<JoyTokenIcon size={16} variant="regular" />}
+                  withDenomination
                 />
                 />
               )}
               )}
             </>
             </>
@@ -163,7 +168,7 @@ export const NftTileDetails: FC<NftTileDetailsProps> = memo(
     const avatars = useMemo(
     const avatars = useMemo(
       () => [
       () => [
         {
         {
-          url: creator?.assetUrl,
+          urls: creator?.assetUrls,
           tooltipText: `Creator: ${creator?.name}`,
           tooltipText: `Creator: ${creator?.name}`,
           onClick: creator?.onClick,
           onClick: creator?.onClick,
           loading: creator?.loading,
           loading: creator?.loading,
@@ -171,7 +176,7 @@ export const NftTileDetails: FC<NftTileDetailsProps> = memo(
         ...(owner
         ...(owner
           ? [
           ? [
               {
               {
-                url: owner?.assetUrl,
+                urls: owner?.assetUrls,
                 tooltipText: `Owner: ${owner?.name}`,
                 tooltipText: `Owner: ${owner?.name}`,
                 onClick: owner?.onClick,
                 onClick: owner?.onClick,
                 loading: owner.loading,
                 loading: owner.loading,
@@ -179,7 +184,7 @@ export const NftTileDetails: FC<NftTileDetailsProps> = memo(
             ]
             ]
           : []),
           : []),
       ],
       ],
-      [creator?.assetUrl, creator?.loading, creator?.name, creator?.onClick, owner]
+      [creator?.assetUrls, creator?.loading, creator?.name, creator?.onClick, owner]
     )
     )
 
 
     return (
     return (
@@ -254,9 +259,10 @@ type DetailsContentProps = {
   content: number | string | ReactElement | ReactElement[]
   content: number | string | ReactElement | ReactElement[]
   secondary?: boolean
   secondary?: boolean
   tileSize: TileSize | undefined
   tileSize: TileSize | undefined
+  withDenomination?: boolean
 }
 }
 export const DetailsContent: FC<DetailsContentProps> = memo(
 export const DetailsContent: FC<DetailsContentProps> = memo(
-  ({ tileSize, caption, icon, content, secondary, avoidIconStyling }) => {
+  ({ tileSize, caption, icon, content, secondary, avoidIconStyling, withDenomination }) => {
     const getSize = () => {
     const getSize = () => {
       switch (tileSize) {
       switch (tileSize) {
         case 'small':
         case 'small':
@@ -277,7 +283,7 @@ export const DetailsContent: FC<DetailsContentProps> = memo(
           {caption}
           {caption}
         </Text>
         </Text>
         <DetailsContentWrapper avoidIconStyling={avoidIconStyling} secondary={secondary}>
         <DetailsContentWrapper avoidIconStyling={avoidIconStyling} secondary={secondary}>
-          {icon}{' '}
+          {typeof content === 'string' && icon}{' '}
           {typeof content === 'string' ? (
           {typeof content === 'string' ? (
             <Text as="span" variant={getSize().content} color={secondary ? 'colorText' : undefined}>
             <Text as="span" variant={getSize().content} color={secondary ? 'colorText' : undefined}>
               {content}
               {content}
@@ -285,10 +291,12 @@ export const DetailsContent: FC<DetailsContentProps> = memo(
           ) : typeof content === 'number' ? (
           ) : typeof content === 'number' ? (
             <NumberFormat
             <NumberFormat
               as="span"
               as="span"
+              icon={icon}
               value={content}
               value={content}
               format="short"
               format="short"
               variant={getSize().content}
               variant={getSize().content}
               color={secondary ? 'colorText' : undefined}
               color={secondary ? 'colorText' : undefined}
+              withDenomination={withDenomination}
             />
             />
           ) : (
           ) : (
             content
             content

+ 7 - 7
packages/atlas/src/components/_nft/NftTileViewer/NftTileViewer.tsx

@@ -19,9 +19,9 @@ type NftTileViewerProps = {
 export const NftTileViewer: FC<NftTileViewerProps> = ({ nftId, isInCarousel }) => {
 export const NftTileViewer: FC<NftTileViewerProps> = ({ nftId, isInCarousel }) => {
   const { nftStatus, nft, loading } = useNft(nftId || '')
   const { nftStatus, nft, loading } = useNft(nftId || '')
   const navigate = useNavigate()
   const navigate = useNavigate()
-  const thumbnailUrl = nft?.video.thumbnailPhoto?.resolvedUrl
+  const thumbnailUrls = nft?.video.thumbnailPhoto?.resolvedUrls
   const nftActions = useNftActions()
   const nftActions = useNftActions()
-  const creatorAvatarUrl = nft?.video.channel.avatarPhoto?.resolvedUrl
+  const creatorAvatarUrls = nft?.video.channel.avatarPhoto?.resolvedUrls
   const nftState = useNftState(nft)
   const nftState = useNftState(nft)
   const {
   const {
     auctionPlannedEndDate,
     auctionPlannedEndDate,
@@ -36,7 +36,7 @@ export const NftTileViewer: FC<NftTileViewerProps> = ({ nftId, isInCarousel }) =
   const ownerMember = nft?.owner.__typename === 'NftOwnerMember' && nft.owner.member
   const ownerMember = nft?.owner.__typename === 'NftOwnerMember' && nft.owner.member
   const ownerChannel = nft?.owner.__typename === 'NftOwnerChannel' && nft.owner.channel
   const ownerChannel = nft?.owner.__typename === 'NftOwnerChannel' && nft.owner.channel
 
 
-  const { url: ownerMemberAvatarUrl } = getMemberAvatar(ownerMember || null)
+  const { urls: ownerMemberAvatarUrls } = getMemberAvatar(ownerMember || null)
 
 
   const isAuction = nftStatus?.status === 'auction'
   const isAuction = nftStatus?.status === 'auction'
 
 
@@ -50,14 +50,14 @@ export const NftTileViewer: FC<NftTileViewerProps> = ({ nftId, isInCarousel }) =
   const owner = ownerChannel
   const owner = ownerChannel
     ? {
     ? {
         name: ownerChannel.title || undefined,
         name: ownerChannel.title || undefined,
-        assetUrl: creatorAvatarUrl || undefined,
+        assetUrls: creatorAvatarUrls || undefined,
         loading,
         loading,
         onClick: () => navigate(absoluteRoutes.viewer.channel(ownerChannel.id)),
         onClick: () => navigate(absoluteRoutes.viewer.channel(ownerChannel.id)),
       }
       }
     : ownerMember
     : ownerMember
     ? {
     ? {
         name: ownerMember.handle,
         name: ownerMember.handle,
-        assetUrl: ownerMemberAvatarUrl,
+        assetUrls: ownerMemberAvatarUrls,
         loading,
         loading,
         onClick: () => navigate(absoluteRoutes.viewer.member(ownerMember.handle)),
         onClick: () => navigate(absoluteRoutes.viewer.member(ownerMember.handle)),
       }
       }
@@ -83,7 +83,7 @@ export const NftTileViewer: FC<NftTileViewerProps> = ({ nftId, isInCarousel }) =
     loading: loading || !nftId,
     loading: loading || !nftId,
     thumbnail: {
     thumbnail: {
       videoHref: absoluteRoutes.viewer.video(nft?.video.id),
       videoHref: absoluteRoutes.viewer.video(nft?.video.id),
-      thumbnailUrl: thumbnailUrl,
+      thumbnailUrls: thumbnailUrls,
       loading: loading,
       loading: loading,
       thumbnailAlt: `${nft?.video?.title} video thumbnail`,
       thumbnailAlt: `${nft?.video?.title} video thumbnail`,
       type: 'video',
       type: 'video',
@@ -92,7 +92,7 @@ export const NftTileViewer: FC<NftTileViewerProps> = ({ nftId, isInCarousel }) =
     creator: {
     creator: {
       name: nft?.video.channel.title || undefined,
       name: nft?.video.channel.title || undefined,
       loading: loading,
       loading: loading,
-      assetUrl: creatorAvatarUrl,
+      assetUrls: creatorAvatarUrls,
       onClick: () => navigate(absoluteRoutes.viewer.channel(nft?.video.channel.id)),
       onClick: () => navigate(absoluteRoutes.viewer.channel(nft?.video.channel.id)),
     },
     },
     contextMenuItems,
     contextMenuItems,

+ 5 - 61
packages/atlas/src/components/_nft/NftWidget/NftHistory.styles.ts

@@ -1,19 +1,15 @@
 import styled from '@emotion/styled'
 import styled from '@emotion/styled'
 
 
-import { Button } from '@/components/_buttons/Button'
 import { cVar, sizes } from '@/styles'
 import { cVar, sizes } from '@/styles'
 
 
 import { SizeProps, sizeObj } from './NftWidget.styles'
 import { SizeProps, sizeObj } from './NftWidget.styles'
 
 
-type OpenProps = { 'data-open': boolean }
-
-export const NftHistoryHeader = styled.div<SizeProps & OpenProps>`
+export const NftHistoryHeader = styled.div<SizeProps>`
   display: grid;
   display: grid;
   grid-template-columns: 1fr auto;
   grid-template-columns: 1fr auto;
   align-items: center;
   align-items: center;
   padding: ${sizes(6)};
   padding: ${sizes(6)};
   user-select: none;
   user-select: none;
-  cursor: pointer;
 
 
   &[data-size=${sizeObj.small}] {
   &[data-size=${sizeObj.small}] {
     padding: ${sizes(4)};
     padding: ${sizes(4)};
@@ -24,58 +20,21 @@ export const NftHistoryHeader = styled.div<SizeProps & OpenProps>`
   }
   }
 `
 `
 
 
-export const StyledChevronButton = styled(Button)<OpenProps>`
-  transform: rotate(0);
-  transform-origin: center;
-  transition: ${cVar('animationTransitionFast')};
-
-  &[data-open='true'] {
-    transform: rotate(180deg);
-  }
-`
-
-type FadingBlockProps = { width: number; 'data-bottom'?: boolean } & SizeProps
-export const FadingBlock = styled.div<FadingBlockProps>`
-  height: ${sizes(6)};
-  background: linear-gradient(0deg, rgb(11 12 15 / 0) 0%, ${cVar('colorCoreNeutral900')} 100%);
-  position: absolute;
-  width: ${({ width }) => width}px;
-  z-index: 1;
-
-  &[data-size=${sizeObj.small}] {
-    height: ${sizes(4)};
-  }
-
-  &[data-bottom] {
-    transform: rotate(180deg);
-    bottom: 0;
-  }
-`
-
-type HistoryPanelProps = SizeProps & OpenProps
+type HistoryPanelProps = SizeProps
 export const HistoryPanel = styled.div<HistoryPanelProps>`
 export const HistoryPanel = styled.div<HistoryPanelProps>`
   background-color: ${cVar('colorBackgroundMuted')};
   background-color: ${cVar('colorBackgroundMuted')};
   position: relative;
   position: relative;
   display: grid;
   display: grid;
   gap: ${sizes(6)};
   gap: ${sizes(6)};
-  max-height: 280px;
-  padding: ${sizes(6)};
+  padding: ${sizes(2)} ${sizes(6)} ${sizes(6)} ${sizes(6)};
   overflow: hidden auto;
   overflow: hidden auto;
-  transition: transform ${cVar('animationTransitionFast')};
-  will-change: transform;
+  max-height: 376px;
 
 
   &[data-size=${sizeObj.small}] {
   &[data-size=${sizeObj.small}] {
+    max-height: 400px;
     gap: ${sizes(4)};
     gap: ${sizes(4)};
     padding: ${sizes(4)};
     padding: ${sizes(4)};
   }
   }
-
-  transform: translateY(-100%);
-  z-index: -1;
-
-  &[data-open='true'] {
-    transform: translateY(0);
-    z-index: unset;
-  }
 `
 `
 
 
 export const HistoryItemContainer = styled.div<SizeProps>`
 export const HistoryItemContainer = styled.div<SizeProps>`
@@ -98,21 +57,6 @@ export const CopyContainer = styled.div`
   display: flex;
   display: flex;
 `
 `
 
 
-export const ValueContainer = styled.div`
-  display: grid;
-  gap: ${sizes(1)};
-  grid-auto-rows: max-content;
-`
-
-export const JoyPlusIcon = styled.div`
-  display: grid;
-  gap: ${sizes(1)};
-  align-items: center;
-  grid-auto-flow: column;
-  grid-auto-columns: max-content;
-  justify-content: end;
-`
-
 export const HistoryPanelContainer = styled.div`
 export const HistoryPanelContainer = styled.div`
   position: relative;
   position: relative;
 `
 `

+ 20 - 44
packages/atlas/src/components/_nft/NftWidget/NftHistory.tsx

@@ -3,54 +3,40 @@ import { FC } from 'react'
 import { useNavigate } from 'react-router'
 import { useNavigate } from 'react-router'
 
 
 import { BasicMembershipFieldsFragment } from '@/api/queries/__generated__/fragments.generated'
 import { BasicMembershipFieldsFragment } from '@/api/queries/__generated__/fragments.generated'
-import { SvgActionChevronB } from '@/assets/icons'
 import { Avatar } from '@/components/Avatar'
 import { Avatar } from '@/components/Avatar'
 import { JoyTokenIcon } from '@/components/JoyTokenIcon'
 import { JoyTokenIcon } from '@/components/JoyTokenIcon'
 import { NumberFormat } from '@/components/NumberFormat'
 import { NumberFormat } from '@/components/NumberFormat'
 import { Text } from '@/components/Text'
 import { Text } from '@/components/Text'
 import { absoluteRoutes } from '@/config/routes'
 import { absoluteRoutes } from '@/config/routes'
-import { useToggle } from '@/hooks/useToggle'
 import { getMemberAvatar } from '@/providers/assets/assets.helpers'
 import { getMemberAvatar } from '@/providers/assets/assets.helpers'
-import { useTokenPrice } from '@/providers/joystream/joystream.hooks'
 import { formatDateTime } from '@/utils/time'
 import { formatDateTime } from '@/utils/time'
 
 
 import {
 import {
   CopyContainer,
   CopyContainer,
-  FadingBlock,
   HistoryItemContainer,
   HistoryItemContainer,
   HistoryPanel,
   HistoryPanel,
   HistoryPanelContainer,
   HistoryPanelContainer,
-  JoyPlusIcon,
   NftHistoryHeader,
   NftHistoryHeader,
-  StyledChevronButton,
   TextContainer,
   TextContainer,
-  ValueContainer,
 } from './NftHistory.styles'
 } from './NftHistory.styles'
 import { OwnerHandle, Size } from './NftWidget.styles'
 import { OwnerHandle, Size } from './NftWidget.styles'
 
 
 type NftHistoryProps = { size: Size; width: number; historyItems: NftHistoryEntry[] }
 type NftHistoryProps = { size: Size; width: number; historyItems: NftHistoryEntry[] }
-export const NftHistory: FC<NftHistoryProps> = ({ size, width, historyItems }) => {
-  const [isOpen, toggleIsOpen] = useToggle()
-
+export const NftHistory: FC<NftHistoryProps> = ({ size, historyItems }) => {
   return (
   return (
     <>
     <>
-      <NftHistoryHeader data-open={isOpen} data-size={size} onClick={toggleIsOpen}>
+      <NftHistoryHeader data-size={size}>
         <Text as="h3" variant={size === 'small' ? 'h300' : 'h400'}>
         <Text as="h3" variant={size === 'small' ? 'h300' : 'h400'}>
           History
           History
         </Text>
         </Text>
-        <StyledChevronButton data-open={isOpen} variant="tertiary" icon={<SvgActionChevronB />} />
       </NftHistoryHeader>
       </NftHistoryHeader>
-      {isOpen && (
-        <HistoryPanelContainer>
-          <FadingBlock data-size={size} width={width} />
-          <HistoryPanel data-size={size} data-open={isOpen}>
-            {historyItems.map((props, index) => (
-              <HistoryItem key={index} {...props} size={size} />
-            ))}
-          </HistoryPanel>
-          <FadingBlock data-size={size} width={width} data-bottom />
-        </HistoryPanelContainer>
-      )}
+      <HistoryPanelContainer>
+        <HistoryPanel data-size={size}>
+          {historyItems.map((props, index) => (
+            <HistoryItem key={index} {...props} size={size} />
+          ))}
+        </HistoryPanel>
+      </HistoryPanelContainer>
     </>
     </>
   )
   )
 }
 }
@@ -66,16 +52,13 @@ type HistoryItemProps = {
 } & NftHistoryEntry
 } & NftHistoryEntry
 export const HistoryItem: FC<HistoryItemProps> = ({ size, member, date, joyAmount, text }) => {
 export const HistoryItem: FC<HistoryItemProps> = ({ size, member, date, joyAmount, text }) => {
   const navigate = useNavigate()
   const navigate = useNavigate()
-  const { url, isLoadingAsset } = getMemberAvatar(member)
-  const { convertHapiToUSD } = useTokenPrice()
-
-  const dollarValue = joyAmount ? convertHapiToUSD(joyAmount) : null
+  const { urls, isLoadingAsset } = getMemberAvatar(member)
 
 
   return (
   return (
     <HistoryItemContainer data-size={size}>
     <HistoryItemContainer data-size={size}>
       <Avatar
       <Avatar
         onClick={() => navigate(absoluteRoutes.viewer.member(member?.handle))}
         onClick={() => navigate(absoluteRoutes.viewer.member(member?.handle))}
-        assetUrl={url}
+        assetUrls={urls}
         loading={isLoadingAsset}
         loading={isLoadingAsset}
         size={size === 'medium' ? 40 : 32}
         size={size === 'medium' ? 40 : 32}
       />
       />
@@ -96,22 +79,15 @@ export const HistoryItem: FC<HistoryItemProps> = ({ size, member, date, joyAmoun
         </Text>
         </Text>
       </TextContainer>
       </TextContainer>
       {!!joyAmount && (
       {!!joyAmount && (
-        <ValueContainer>
-          <JoyPlusIcon>
-            <JoyTokenIcon size={16} variant="silver" />
-            <NumberFormat as="span" format="short" value={joyAmount} variant={size === 'medium' ? 'h300' : 'h200'} />
-          </JoyPlusIcon>
-          {dollarValue !== null && (
-            <NumberFormat
-              as="span"
-              format="dollar"
-              variant="t100"
-              color="colorText"
-              value={dollarValue || 0}
-              align="end"
-            />
-          )}
-        </ValueContainer>
+        <NumberFormat
+          as="span"
+          icon={<JoyTokenIcon size={16} variant="silver" />}
+          format="short"
+          value={joyAmount}
+          variant={size === 'medium' ? 'h300' : 'h200'}
+          withDenomination
+          denominationAlign="right"
+        />
       )}
       )}
     </HistoryItemContainer>
     </HistoryItemContainer>
   )
   )

+ 10 - 8
packages/atlas/src/components/_nft/NftWidget/NftWidget.hooks.ts

@@ -83,9 +83,11 @@ export const useNftWidget = (video: FullVideoFieldsFragment | undefined | null):
   const ownerMember = nftOwner?.__typename === 'NftOwnerMember' ? nftOwner.member : null
   const ownerMember = nftOwner?.__typename === 'NftOwnerMember' ? nftOwner.member : null
   const ownerChannel = nftOwner?.__typename === 'NftOwnerChannel' ? nftOwner.channel : null
   const ownerChannel = nftOwner?.__typename === 'NftOwnerChannel' ? nftOwner.channel : null
 
 
-  const { url: ownerAvatarUri } = getMemberAvatar(ownerMember)
-  const creatorAvatarUri = ownerChannel?.avatarPhoto?.resolvedUrl
-  const { url: topBidderAvatarUri } = getMemberAvatar(nftStatus?.status === 'auction' ? nftStatus.topBidder : undefined)
+  const { urls: _ownerAvatarUrls } = getMemberAvatar(ownerMember)
+  const creatorAvatarUrls = ownerChannel?.avatarPhoto?.resolvedUrls
+  const { urls: topBidderAvatarUris } = getMemberAvatar(
+    nftStatus?.status === 'auction' ? nftStatus.topBidder : undefined
+  )
 
 
   const { entries: nftHistory } = useNftHistoryEntries(video?.id ?? '', {
   const { entries: nftHistory } = useNftHistoryEntries(video?.id ?? '', {
     skip: !nft,
     skip: !nft,
@@ -95,7 +97,7 @@ export const useNftWidget = (video: FullVideoFieldsFragment | undefined | null):
   })
   })
   const isOwnedByChannel = nftOwner?.__typename === 'NftOwnerChannel'
   const isOwnedByChannel = nftOwner?.__typename === 'NftOwnerChannel'
   const ownerHandle = ownerMember?.handle || ownerChannel?.title
   const ownerHandle = ownerMember?.handle || ownerChannel?.title
-  const ownerAvatar = isOwnedByChannel ? creatorAvatarUri : ownerAvatarUri
+  const ownerAvatarUrls = isOwnedByChannel ? creatorAvatarUrls : _ownerAvatarUrls
 
 
   const creatorId = ownerMember?.id || ownerChannel?.id
   const creatorId = ownerMember?.id || ownerChannel?.id
 
 
@@ -103,7 +105,7 @@ export const useNftWidget = (video: FullVideoFieldsFragment | undefined | null):
     case 'auction': {
     case 'auction': {
       return {
       return {
         ownerHandle,
         ownerHandle,
-        ownerAvatar,
+        ownerAvatarUrls,
         creatorId,
         creatorId,
         isOwner,
         isOwner,
         needsSettling,
         needsSettling,
@@ -115,7 +117,7 @@ export const useNftWidget = (video: FullVideoFieldsFragment | undefined | null):
           canChangeBid,
           canChangeBid,
           englishTimerState,
           englishTimerState,
           auctionPlannedEndDate,
           auctionPlannedEndDate,
-          topBidderAvatarUri,
+          topBidderAvatarUris,
           isUserTopBidder,
           isUserTopBidder,
           userBidUnlockDate,
           userBidUnlockDate,
           startsAtBlock,
           startsAtBlock,
@@ -137,7 +139,7 @@ export const useNftWidget = (video: FullVideoFieldsFragment | undefined | null):
     case 'buy-now':
     case 'buy-now':
       return {
       return {
         ownerHandle,
         ownerHandle,
-        ownerAvatar,
+        ownerAvatarUrls,
         creatorId,
         creatorId,
         isOwner,
         isOwner,
         needsSettling,
         needsSettling,
@@ -154,7 +156,7 @@ export const useNftWidget = (video: FullVideoFieldsFragment | undefined | null):
     case 'idle':
     case 'idle':
       return {
       return {
         ownerHandle,
         ownerHandle,
-        ownerAvatar,
+        ownerAvatarUrls,
         creatorId,
         creatorId,
         isOwner,
         isOwner,
         needsSettling,
         needsSettling,

+ 46 - 48
packages/atlas/src/components/_nft/NftWidget/NftWidget.styles.ts

@@ -1,6 +1,8 @@
+import isPropValid from '@emotion/is-prop-valid'
 import styled from '@emotion/styled'
 import styled from '@emotion/styled'
 import { Link } from 'react-router-dom'
 import { Link } from 'react-router-dom'
 
 
+import { SvgActionChevronT } from '@/assets/icons'
 import { Avatar } from '@/components/Avatar'
 import { Avatar } from '@/components/Avatar'
 import { Text } from '@/components/Text'
 import { Text } from '@/components/Text'
 import { cVar, sizes } from '@/styles'
 import { cVar, sizes } from '@/styles'
@@ -13,13 +15,22 @@ export const Container = styled.div`
   background-color: ${cVar('colorBackgroundMuted')};
   background-color: ${cVar('colorBackgroundMuted')};
   min-width: 0;
   min-width: 0;
 `
 `
+export const CollapsibleWrapper = styled.div<{ collapsed: boolean }>`
+  display: grid;
+  grid-template-rows: ${({ collapsed }) => (collapsed ? '0fr' : '1fr')};
+  transition: grid-template-rows ${cVar('animationTransitionMedium')};
+`
+
+export const CollapsibleElement = styled.div`
+  overflow: hidden;
+`
 
 
 export const Content = styled.div<SizeProps>`
 export const Content = styled.div<SizeProps>`
   display: grid;
   display: grid;
   gap: ${sizes(6)};
   gap: ${sizes(6)};
   grid-template-columns: 1fr 1fr;
   grid-template-columns: 1fr 1fr;
   justify-content: space-between;
   justify-content: space-between;
-  box-shadow: ${cVar('effectDividersTop')}, ${cVar('effectDividersBottom')};
+  box-shadow: ${cVar('effectDividersBottom')};
   padding: ${sizes(6)};
   padding: ${sizes(6)};
 
 
   &[data-size=${sizeObj.small}] {
   &[data-size=${sizeObj.small}] {
@@ -31,10 +42,11 @@ export const Content = styled.div<SizeProps>`
 
 
 export const NftOwnerContainer = styled.div<SizeProps>`
 export const NftOwnerContainer = styled.div<SizeProps>`
   display: grid;
   display: grid;
+  box-shadow: ${cVar('effectDividersBottom')};
   gap: ${sizes(1)} ${sizes(6)};
   gap: ${sizes(1)} ${sizes(6)};
   grid-template:
   grid-template:
-    'avatar owner-label' auto
-    'avatar owner' auto / auto 1fr;
+    'avatar owner-label collapsible-button' auto
+    'avatar owner collapsible-button' auto / min-content auto auto;
   align-items: center;
   align-items: center;
   padding: ${sizes(6)};
   padding: ${sizes(6)};
 
 
@@ -44,62 +56,48 @@ export const NftOwnerContainer = styled.div<SizeProps>`
   }
   }
 `
 `
 
 
-export const OwnerAvatar = styled(Avatar)`
-  grid-area: avatar;
+export const StatusContainer = styled.div`
+  background-color: ${cVar('colorBackground')};
+  padding: ${sizes(1)} ${sizes(6)};
+  display: flex;
+  gap: ${sizes(2)};
+  align-items: center;
 `
 `
 
 
-export const OwnerLabel = styled(Text)`
-  grid-area: owner-label;
+export const StatusMark = styled.div`
+  width: 11px;
+  height: 11px;
+  background-color: ${cVar('colorTextSuccess')};
+  border-radius: 12px;
+  border: 1px solid ${cVar('colorBackgroundElevatedAlpha')};
 `
 `
 
 
-export const OwnerHandle = styled(Link)`
-  grid-area: owner;
-  justify-content: start;
-  text-decoration: none;
+export const StyledSvgActionChevronT = styled(SvgActionChevronT, {
+  shouldForwardProp: isPropValid,
+})<{ isCollapsed: boolean }>`
+  transform: rotate(${({ isCollapsed }) => (isCollapsed ? '-180deg' : '0deg')});
+  transition: transform ${cVar('animationTransitionMedium')};
 `
 `
 
 
-export const ButtonGrid = styled.div<SizeProps & { 'data-two-columns'?: boolean }>`
-  display: grid;
-  gap: ${sizes(4)};
-
-  &[data-size=${sizeObj.small}] {
-    gap: ${sizes(2)};
-  }
+export const OwnerAvatar = styled(Avatar)`
+  grid-area: avatar;
+`
 
 
-  &[data-two-columns='true'] {
-    grid-template-columns: 1fr 1fr;
-  }
+export const OwnerLabel = styled(Text)`
+  grid-area: owner-label;
 `
 `
 
 
-export const TopBidderTokenContainer = styled.div<SizeProps>`
+export const CollapsibleButtonWrapper = styled.div`
+  grid-area: collapsible-button;
+  justify-self: end;
   display: flex;
   display: flex;
+  gap: ${sizes(3)};
   align-items: center;
   align-items: center;
-  position: relative;
-  left: -4px;
-  z-index: 10;
-
-  &::before {
-    display: inline-block;
-    position: absolute;
-    content: '';
-    width: 28px;
-    height: 28px;
-    background: ${cVar('colorBackgroundMuted')};
-    border-radius: 100%;
-    left: -2px;
-    top: -2px;
-  }
-
-  &[data-size=${sizeObj.small}] {
-    &::before {
-      width: 21px;
-      height: 21px;
-      left: -2.5px;
-      top: 1.5px;
-    }
-  }
 `
 `
 
 
-export const TopBidderContainer = styled.div`
-  display: flex;
+export const OwnerHandle = styled(Link)`
+  grid-area: owner;
+  justify-content: start;
+  justify-self: start;
+  text-decoration: none;
 `
 `

+ 72 - 542
packages/atlas/src/components/_nft/NftWidget/NftWidget.tsx

@@ -1,29 +1,19 @@
 import BN from 'bn.js'
 import BN from 'bn.js'
-import { differenceInSeconds } from 'date-fns'
-import { FC, memo } from 'react'
+import { FC, useEffect, useState } from 'react'
+import { useLocation } from 'react-router'
 import useResizeObserver from 'use-resize-observer'
 import useResizeObserver from 'use-resize-observer'
 
 
-import { BasicBidFieldsFragment, FullBidFieldsFragment } from '@/api/queries/__generated__/fragments.generated'
-import { SvgAlertsInformative24 } from '@/assets/icons'
-import { Avatar } from '@/components/Avatar'
-import { Banner } from '@/components/Banner'
-import { JoyTokenIcon } from '@/components/JoyTokenIcon'
-import { GridItem } from '@/components/LayoutGrid'
-import { NumberFormat } from '@/components/NumberFormat'
+import { FullBidFieldsFragment } from '@/api/queries/__generated__/fragments.generated'
 import { Text } from '@/components/Text'
 import { Text } from '@/components/Text'
 import { Button } from '@/components/_buttons/Button'
 import { Button } from '@/components/_buttons/Button'
 import { absoluteRoutes } from '@/config/routes'
 import { absoluteRoutes } from '@/config/routes'
-import { useDeepMemo } from '@/hooks/useDeepMemo'
-import { useMsTimestamp } from '@/hooks/useMsTimestamp'
-import { EnglishTimerState } from '@/hooks/useNftState'
 import { NftSaleType } from '@/joystream-lib/types'
 import { NftSaleType } from '@/joystream-lib/types'
-import { useTokenPrice } from '@/providers/joystream/joystream.hooks'
-import { formatDateTime, formatDurationShort, formatTime } from '@/utils/time'
 
 
 import { NftHistory, NftHistoryEntry } from './NftHistory'
 import { NftHistory, NftHistoryEntry } from './NftHistory'
-import { NftInfoItem, NftTimerItem } from './NftInfoItem'
 import {
 import {
-  ButtonGrid,
+  CollapsibleButtonWrapper,
+  CollapsibleElement,
+  CollapsibleWrapper,
   Container,
   Container,
   Content,
   Content,
   NftOwnerContainer,
   NftOwnerContainer,
@@ -31,67 +21,34 @@ import {
   OwnerHandle,
   OwnerHandle,
   OwnerLabel,
   OwnerLabel,
   Size,
   Size,
-  TopBidderContainer,
-  TopBidderTokenContainer,
+  StatusContainer,
+  StatusMark,
+  StyledSvgActionChevronT,
 } from './NftWidget.styles'
 } from './NftWidget.styles'
-
-export type Auction = {
-  status: 'auction'
-  type: 'open' | 'english'
-  startingPrice: BN
-  buyNowPrice: BN | undefined
-  topBid: BasicBidFieldsFragment | undefined
-  topBidAmount: BN | undefined
-  topBidderHandle: string | undefined
-  topBidderAvatarUri: string | null | undefined
-  isUserTopBidder: boolean | undefined
-  userBidAmount: BN | undefined
-  userBidUnlockDate: Date | undefined
-  canWithdrawBid: boolean | undefined
-  canChangeBid: boolean | undefined
-  hasTimersLoaded: boolean | undefined
-  englishTimerState: EnglishTimerState | undefined
-  auctionPlannedEndDate: Date | undefined
-  startsAtDate: Date | undefined
-  plannedEndAtBlock: number | null | undefined
-  startsAtBlock: number | null | undefined
-  auctionBeginsInDays: number
-  auctionBeginsInSeconds: number
-  isUserWhitelisted: boolean | undefined
-}
+import { NftWidgetStatus } from './NftWidget.types'
+import { NftWidgetContent } from './NftWidgetContent'
 
 
 export type NftWidgetProps = {
 export type NftWidgetProps = {
   ownerHandle: string | null | undefined
   ownerHandle: string | null | undefined
-  ownerAvatar: string | null | undefined
+  ownerAvatarUrls: string[] | null | undefined
   creatorId?: string
   creatorId?: string
-  isOwner: boolean | undefined
-  needsSettling: boolean | undefined
-  bidFromPreviousAuction: FullBidFieldsFragment | undefined
   saleType: NftSaleType | null
   saleType: NftSaleType | null
-  nftStatus?:
-    | {
-        status: 'idle'
-        lastSalePrice: BN | undefined
-        lastSaleDate: Date | undefined
-      }
-    | {
-        status: 'buy-now'
-        buyNowPrice: BN
-      }
-    | Auction
-    | undefined
+  isOwnedByChannel?: boolean
+  nftStatus: NftWidgetStatus | undefined
   nftHistory: NftHistoryEntry[]
   nftHistory: NftHistoryEntry[]
+  isOwner: boolean | undefined
+  needsSettling: boolean | undefined
+  onNftPutOnSale?: () => void
+  onNftAcceptBid?: () => void
   onNftPurchase?: () => void
   onNftPurchase?: () => void
+  onWithdrawBid?: (bid?: BN, createdAt?: Date) => void
+  bidFromPreviousAuction: FullBidFieldsFragment | undefined
   onNftSettlement?: () => void
   onNftSettlement?: () => void
   onNftBuyNow?: () => void
   onNftBuyNow?: () => void
-  onNftPutOnSale?: () => void
-  onNftAcceptBid?: () => void
   onNftCancelSale?: () => void
   onNftCancelSale?: () => void
   onNftChangePrice?: () => void
   onNftChangePrice?: () => void
-  onWithdrawBid?: (bid?: BN, createdAt?: Date) => void
   userBidCreatedAt?: Date
   userBidCreatedAt?: Date
   userBidAmount?: BN
   userBidAmount?: BN
-  isOwnedByChannel?: boolean
 }
 }
 
 
 const SMALL_VARIANT_MAXIMUM_SIZE = 416
 const SMALL_VARIANT_MAXIMUM_SIZE = 416
@@ -99,11 +56,12 @@ const SMALL_VARIANT_MAXIMUM_SIZE = 416
 export const NftWidget: FC<NftWidgetProps> = ({
 export const NftWidget: FC<NftWidgetProps> = ({
   ownerHandle,
   ownerHandle,
   creatorId,
   creatorId,
-  isOwner,
   nftStatus,
   nftStatus,
   nftHistory,
   nftHistory,
+  isOwnedByChannel,
+  ownerAvatarUrls,
+  isOwner,
   needsSettling,
   needsSettling,
-  ownerAvatar,
   onNftPutOnSale,
   onNftPutOnSale,
   onNftAcceptBid,
   onNftAcceptBid,
   onWithdrawBid,
   onWithdrawBid,
@@ -115,494 +73,28 @@ export const NftWidget: FC<NftWidgetProps> = ({
   onNftBuyNow,
   onNftBuyNow,
   userBidCreatedAt,
   userBidCreatedAt,
   userBidAmount,
   userBidAmount,
-  isOwnedByChannel,
 }) => {
 }) => {
-  const timestamp = useMsTimestamp()
   const { ref, width = SMALL_VARIANT_MAXIMUM_SIZE + 1 } = useResizeObserver({
   const { ref, width = SMALL_VARIANT_MAXIMUM_SIZE + 1 } = useResizeObserver({
     box: 'border-box',
     box: 'border-box',
   })
   })
 
 
-  const size: Size = width > SMALL_VARIANT_MAXIMUM_SIZE ? 'medium' : 'small'
-  const { convertHapiToUSD, isLoadingPrice } = useTokenPrice()
-
-  const content = useDeepMemo(() => {
-    if (!nftStatus) {
-      return
-    }
-    const contentTextVariant = size === 'small' ? 'h400' : 'h600'
-    const buttonSize = size === 'small' ? 'medium' : 'large'
-    const buttonColumnSpan = size === 'small' ? 1 : 2
-    const timerColumnSpan = size === 'small' ? 1 : 2
-
-    const BuyNow = memo(({ buyNowPrice }: { buyNowPrice?: BN }) => {
-      const buyNowPriceInUsd = buyNowPrice && convertHapiToUSD(buyNowPrice)
-      return buyNowPrice?.gtn(0) ? (
-        <NftInfoItem
-          size={size}
-          label="Buy now"
-          disableSecondary={buyNowPriceInUsd === null}
-          content={
-            <>
-              <JoyTokenIcon size={size === 'small' ? 16 : 24} variant="silver" />
-              <NumberFormat as="span" value={buyNowPrice} format="short" variant={contentTextVariant} />
-            </>
-          }
-          secondaryText={
-            buyNowPriceInUsd && <NumberFormat as="span" color="colorText" format="dollar" value={buyNowPriceInUsd} />
-          }
-        />
-      ) : null
-    })
-    BuyNow.displayName = 'BuyNow'
-    const InfoBanner = ({ title, description }: { title: string; description: string }) => (
-      <GridItem colSpan={buttonColumnSpan}>
-        <Banner icon={<SvgAlertsInformative24 />} {...{ title, description }} />
-      </GridItem>
-    )
-
-    const WithdrawBidFromPreviousAuction = ({ secondary }: { secondary?: boolean }) =>
-      bidFromPreviousAuction ? (
-        <>
-          <GridItem colSpan={buttonColumnSpan}>
-            <Button
-              variant={secondary ? 'secondary' : undefined}
-              fullWidth
-              size={buttonSize}
-              onClick={() =>
-                onWithdrawBid?.(new BN(bidFromPreviousAuction.amount), new Date(bidFromPreviousAuction.createdAt))
-              }
-            >
-              Withdraw last bid
-            </Button>
-            <Text as="p" margin={{ top: 2 }} variant="t100" color="colorText" align="center">
-              You bid{' '}
-              <NumberFormat
-                as="span"
-                value={new BN(bidFromPreviousAuction?.amount)}
-                format="short"
-                variant="t100"
-                color="colorText"
-                withToken
-              />{' '}
-              on {formatDateTime(new Date(bidFromPreviousAuction.createdAt))}
-            </Text>
-          </GridItem>
-        </>
-      ) : null
+  const location = useLocation()
+  const [isCollapsed, setIsCollapsed] = useState(true)
 
 
-    const BidPlacingInfoText = () => (
-      <Text as="p" variant="t100" color="colorText" align="center">
-        Placing a bid will withdraw your last bid
-      </Text>
-    )
+  const shouldCollapse = location.state?.shouldCollapse === undefined ? true : location.state?.shouldCollapse
 
 
-    switch (nftStatus.status) {
-      case 'idle':
-        return (
-          <>
-            {nftStatus.lastSalePrice ? (
-              <NftInfoItem
-                size={size}
-                label="Last price"
-                content={
-                  <>
-                    <JoyTokenIcon size={size === 'small' ? 16 : 24} variant="silver" />
-                    <NumberFormat
-                      as="span"
-                      value={nftStatus.lastSalePrice}
-                      format="short"
-                      variant={contentTextVariant}
-                      color="colorText"
-                    />
-                  </>
-                }
-                secondaryText={nftStatus.lastSaleDate && formatDateTime(nftStatus.lastSaleDate)}
-              />
-            ) : (
-              <NftInfoItem
-                size={size}
-                label="status"
-                content={
-                  <Text as="span" variant={contentTextVariant} color="colorText">
-                    Not for sale
-                  </Text>
-                }
-              />
-            )}
-            {bidFromPreviousAuction && (
-              <>
-                <InfoBanner
-                  title="Withdraw your bid"
-                  description="You placed a bid in a previous auction that you can now withdraw to claim back your money."
-                />
-                <WithdrawBidFromPreviousAuction />
-              </>
-            )}
-            {isOwner && (
-              <GridItem colSpan={buttonColumnSpan}>
-                <Button fullWidth variant="secondary" size={buttonSize} onClick={onNftPutOnSale}>
-                  Start sale of this NFT
-                </Button>
-              </GridItem>
-            )}
-          </>
-        )
-      case 'buy-now':
-        return (
-          <>
-            <BuyNow buyNowPrice={nftStatus.buyNowPrice} />
+  useEffect(() => {
+    setIsCollapsed(shouldCollapse)
+  }, [shouldCollapse])
 
 
-            <GridItem colSpan={buttonColumnSpan}>
-              <ButtonGrid data-size={size}>
-                {isOwner ? (
-                  <>
-                    <Button fullWidth variant="secondary" size={buttonSize} onClick={onNftChangePrice}>
-                      Change price
-                    </Button>
-                    <Button fullWidth variant="destructive" size={buttonSize} onClick={onNftCancelSale}>
-                      Remove from sale
-                    </Button>
-                  </>
-                ) : (
-                  <GridItem colSpan={buttonColumnSpan}>
-                    <Button fullWidth size={buttonSize} onClick={onNftPurchase}>
-                      Buy now
-                    </Button>
-                  </GridItem>
-                )}
-                {bidFromPreviousAuction && (
-                  <>
-                    <InfoBanner
-                      title="Withdraw your bid"
-                      description="You placed a bid in a previous auction that you can now withdraw to claim back your money."
-                    />
-                    <WithdrawBidFromPreviousAuction secondary />
-                  </>
-                )}
-              </ButtonGrid>
-            </GridItem>
-          </>
-        )
-      case 'auction': {
-        const getInfoBannerProps = () => {
-          const hasBids = !nftStatus.topBid?.isCanceled && nftStatus.topBidAmount?.gtn(0)
-          if (nftStatus.type === 'open' && bidFromPreviousAuction) {
-            return {
-              title: 'Withdraw your bid to participate',
-              description:
-                'You placed a bid in a previous auction that you can now withdraw to be able to participate in this auction.',
-            }
-          }
-
-          if (nftStatus.englishTimerState === 'expired' && isOwner && !hasBids) {
-            return {
-              title: 'Auction ended',
-              description: 'This auction has ended and no one placed a bid. You can now remove this NFT from sale.',
-            }
-          }
-          if (nftStatus.englishTimerState === 'expired' && !bidFromPreviousAuction && !hasBids && !isOwner) {
-            return {
-              title: 'Auction ended',
-              description:
-                "This auction has ended and no one placed a bid. We're waiting for the NFT owner to remove this NFT from sale.",
-            }
-          }
-          if (
-            nftStatus.englishTimerState === 'expired' &&
-            !bidFromPreviousAuction &&
-            hasBids &&
-            !isOwner &&
-            !nftStatus.isUserTopBidder
-          ) {
-            return {
-              title: 'Auction ended',
-              description:
-                'We are waiting for this auction to be settled by the auction winner or the current NFT owner.',
-            }
-          }
-          if (nftStatus.englishTimerState === 'expired' && bidFromPreviousAuction) {
-            return {
-              title: 'Withdraw your bid',
-              description: 'You placed a bid in a previous auction that you can now withdraw.',
-            }
-          }
-
-          if (nftStatus.englishTimerState === 'running' && bidFromPreviousAuction) {
-            return {
-              title: 'Withdraw your bid to participate',
-              description:
-                'You placed a bid in a previous auction that you can now withdraw to be able to participate in this auction.',
-            }
-          }
-
-          if (nftStatus.englishTimerState === 'upcoming' && bidFromPreviousAuction) {
-            return {
-              title: 'Withdraw your bid to participate',
-              description:
-                'You placed a bid in a previous auction that you can now withdraw to be able to participate in this upcoming auction.',
-            }
-          }
-
-          if (nftStatus.isUserWhitelisted === false) {
-            return {
-              title: "You're not on the whitelist",
-              description: `This sale is available only to members whitelisted by ${ownerHandle}.`,
-            }
-          }
-
-          return null
-        }
-        const infoBannerProps = getInfoBannerProps()
-
-        const infoTextNode = !!nftStatus.userBidAmount?.gtn(0) && nftStatus.userBidUnlockDate && (
-          <GridItem colSpan={buttonColumnSpan}>
-            {nftStatus.type === 'english' ? (
-              <BidPlacingInfoText />
-            ) : (
-              <Text as="p" variant="t100" color="colorText" align="center">
-                {nftStatus.canWithdrawBid ? `Your last bid: ` : `Your last bid (`}
-                <NumberFormat as="span" value={nftStatus.userBidAmount} format="short" withToken />
-                {nftStatus.canWithdrawBid
-                  ? ''
-                  : `) becomes withdrawable on ${formatDateTime(nftStatus.userBidUnlockDate)}`}
-              </Text>
-            )}
-          </GridItem>
-        )
-
-        const topBidAmountInUsd = nftStatus.topBidAmount && convertHapiToUSD(nftStatus.topBidAmount)
-        const startingPriceInUsd = convertHapiToUSD(nftStatus.startingPrice)
-
-        return (
-          <>
-            {nftStatus.topBidAmount?.gtn(0) && !nftStatus.topBid?.isCanceled ? (
-              <NftInfoItem
-                size={size}
-                label="Top bid"
-                content={
-                  <>
-                    <TopBidderContainer>
-                      <Avatar assetUrl={nftStatus.topBidderAvatarUri} size={24} />
-                      <TopBidderTokenContainer data-size={size}>
-                        <JoyTokenIcon size={size === 'small' ? 16 : 24} variant="silver" />
-                      </TopBidderTokenContainer>
-                    </TopBidderContainer>
-                    <NumberFormat
-                      as="span"
-                      format="short"
-                      value={nftStatus.topBidAmount}
-                      variant={contentTextVariant}
-                    />
-                  </>
-                }
-                secondaryText={
-                  !isLoadingPrice && nftStatus.topBidderHandle ? (
-                    <>
-                      {topBidAmountInUsd ? (
-                        <NumberFormat as="span" color="colorText" format="dollar" value={topBidAmountInUsd} />
-                      ) : null}{' '}
-                      from{' '}
-                      <OwnerHandle to={absoluteRoutes.viewer.member(nftStatus.topBidderHandle)}>
-                        <Text as="span" variant="t100">
-                          {nftStatus.isUserTopBidder ? 'you' : nftStatus.topBidderHandle}
-                        </Text>
-                      </OwnerHandle>
-                    </>
-                  ) : null
-                }
-              />
-            ) : (
-              <NftInfoItem
-                size={size}
-                label="Starting Price"
-                content={
-                  <>
-                    <JoyTokenIcon size={size === 'small' ? 16 : 24} variant="silver" />
-                    <NumberFormat
-                      as="span"
-                      format="short"
-                      value={nftStatus.startingPrice}
-                      variant={contentTextVariant}
-                    />
-                  </>
-                }
-                disableSecondary={startingPriceInUsd === null}
-                secondaryText={
-                  startingPriceInUsd && (
-                    <NumberFormat as="span" color="colorText" format="dollar" value={startingPriceInUsd ?? 0} />
-                  )
-                }
-              />
-            )}
-            <BuyNow buyNowPrice={nftStatus.buyNowPrice} />
-
-            {nftStatus.englishTimerState === 'expired' && (
-              <GridItem colSpan={timerColumnSpan}>
-                <NftInfoItem
-                  size={size}
-                  label="Auction ended on"
-                  loading={!nftStatus.auctionPlannedEndDate}
-                  content={
-                    nftStatus.auctionPlannedEndDate && (
-                      <Text as="span" variant={contentTextVariant} color="colorText">
-                        {formatDateTime(nftStatus.auctionPlannedEndDate)}
-                      </Text>
-                    )
-                  }
-                />
-              </GridItem>
-            )}
-            {nftStatus.englishTimerState === 'running' && nftStatus?.auctionPlannedEndDate && (
-              <GridItem colSpan={timerColumnSpan}>
-                <NftTimerItem size={size} time={nftStatus.auctionPlannedEndDate} />
-              </GridItem>
-            )}
-            {nftStatus.startsAtBlock && nftStatus.auctionBeginsInSeconds >= 0 && (
-              <GridItem colSpan={timerColumnSpan}>
-                <NftInfoItem
-                  size={size}
-                  label="Auction begins on"
-                  loading={!nftStatus.startsAtDate}
-                  content={
-                    nftStatus.startsAtDate && (
-                      <Text as="span" variant={contentTextVariant} color="colorText">
-                        {nftStatus.auctionBeginsInDays > 1 && formatDateTime(nftStatus.startsAtDate)}
-                        {nftStatus.auctionBeginsInDays === 1 && `Tomorrow at ${formatTime(nftStatus.startsAtDate)}`}
-                        {nftStatus.auctionBeginsInDays < 1 &&
-                          formatDurationShort(differenceInSeconds(nftStatus.startsAtDate, timestamp))}
-                      </Text>
-                    )
-                  }
-                />
-              </GridItem>
-            )}
-
-            {nftStatus.hasTimersLoaded && infoBannerProps && <InfoBanner {...infoBannerProps} />}
-
-            {nftStatus.hasTimersLoaded && needsSettling && (nftStatus.isUserTopBidder || isOwner) && (
-              <GridItem colSpan={buttonColumnSpan}>
-                <Button fullWidth size={buttonSize} onClick={onNftSettlement}>
-                  Settle auction
-                </Button>
-              </GridItem>
-            )}
-
-            {nftStatus.hasTimersLoaded && bidFromPreviousAuction && <WithdrawBidFromPreviousAuction />}
-
-            {nftStatus.hasTimersLoaded &&
-              !needsSettling &&
-              !bidFromPreviousAuction &&
-              (isOwner
-                ? (nftStatus.type === 'open' ||
-                    // english auction with no bids
-                    !nftStatus.topBidAmount ||
-                    nftStatus.topBid?.isCanceled) && (
-                    <GridItem colSpan={buttonColumnSpan}>
-                      <ButtonGrid data-size={size}>
-                        {nftStatus.type === 'open' && nftStatus.topBid && !nftStatus.topBid?.isCanceled && (
-                          <Button fullWidth size={buttonSize} onClick={onNftAcceptBid}>
-                            Review and accept bid
-                          </Button>
-                        )}
-                        <Button
-                          fullWidth
-                          onClick={onNftCancelSale}
-                          variant={
-                            nftStatus.type === 'open' && !nftStatus.topBid?.isCanceled
-                              ? 'destructive-secondary'
-                              : 'destructive'
-                          }
-                          size={buttonSize}
-                        >
-                          Remove from sale
-                        </Button>
-                      </ButtonGrid>
-                    </GridItem>
-                  )
-                : nftStatus.englishTimerState === 'running' &&
-                  nftStatus.isUserWhitelisted !== false &&
-                  (nftStatus.buyNowPrice?.gtn(0) ? (
-                    <GridItem colSpan={buttonColumnSpan}>
-                      <ButtonGrid data-size={size} data-two-columns={size === 'medium'}>
-                        <Button fullWidth variant="secondary" size={buttonSize} onClick={onNftPurchase}>
-                          {nftStatus.canChangeBid ? 'Change bid' : 'Place bid'}
-                        </Button>
-                        <Button fullWidth size={buttonSize} onClick={onNftBuyNow}>
-                          Buy now
-                        </Button>
-                        {/* second row button */}
-                        {nftStatus.canWithdrawBid && (
-                          <GridItem colSpan={buttonColumnSpan}>
-                            <Button
-                              fullWidth
-                              size={buttonSize}
-                              variant="destructive-secondary"
-                              onClick={() => onWithdrawBid?.(userBidAmount, userBidCreatedAt)}
-                            >
-                              Withdraw bid
-                            </Button>
-                          </GridItem>
-                        )}
-
-                        {infoTextNode}
-                      </ButtonGrid>
-                    </GridItem>
-                  ) : (
-                    <GridItem colSpan={buttonColumnSpan}>
-                      <ButtonGrid data-size={size}>
-                        <GridItem colSpan={buttonColumnSpan}>
-                          <Button fullWidth size={buttonSize} onClick={onNftPurchase}>
-                            {nftStatus.canChangeBid ? 'Change bid' : 'Place bid'}
-                          </Button>
-                        </GridItem>
-                        {nftStatus.canWithdrawBid && (
-                          <GridItem colSpan={buttonColumnSpan}>
-                            <Button
-                              fullWidth
-                              size={buttonSize}
-                              variant="destructive-secondary"
-                              onClick={() => onWithdrawBid?.(userBidAmount, userBidCreatedAt)}
-                            >
-                              Withdraw bid
-                            </Button>
-                          </GridItem>
-                        )}
-                        {infoTextNode}
-                      </ButtonGrid>
-                    </GridItem>
-                  )))}
-          </>
-        )
-      }
-    }
-  }, [
-    nftStatus,
-    size,
-    convertHapiToUSD,
-    bidFromPreviousAuction,
-    onWithdrawBid,
-    isOwner,
-    onNftPutOnSale,
-    onNftChangePrice,
-    onNftCancelSale,
-    onNftPurchase,
-    isLoadingPrice,
-    timestamp,
-    needsSettling,
-    onNftSettlement,
-    onNftAcceptBid,
-    onNftBuyNow,
-    ownerHandle,
-    userBidAmount,
-    userBidCreatedAt,
-  ])
+  const size: Size = width > SMALL_VARIANT_MAXIMUM_SIZE ? 'medium' : 'small'
 
 
   if (!nftStatus) return null
   if (!nftStatus) return null
 
 
   return (
   return (
     <Container ref={ref}>
     <Container ref={ref}>
       <NftOwnerContainer data-size={size}>
       <NftOwnerContainer data-size={size}>
-        <OwnerAvatar assetUrl={ownerAvatar} size={40} />
+        <OwnerAvatar assetUrls={ownerAvatarUrls} size={40} />
         <OwnerLabel as="span" variant="t100" color="colorText">
         <OwnerLabel as="span" variant="t100" color="colorText">
           This NFT is owned by
           This NFT is owned by
         </OwnerLabel>
         </OwnerLabel>
@@ -619,10 +111,48 @@ export const NftWidget: FC<NftWidgetProps> = ({
             {ownerHandle}
             {ownerHandle}
           </Text>
           </Text>
         </OwnerHandle>
         </OwnerHandle>
+        <CollapsibleButtonWrapper>
+          <Button
+            icon={<StyledSvgActionChevronT isCollapsed={isCollapsed} />}
+            variant="tertiary"
+            size="small"
+            onClick={() => setIsCollapsed((isCollapsed) => !isCollapsed)}
+          />
+        </CollapsibleButtonWrapper>
       </NftOwnerContainer>
       </NftOwnerContainer>
-      <Content data-size={size}>{content}</Content>
-
-      <NftHistory size={size} width={width} historyItems={nftHistory} />
+      {nftStatus.status !== 'idle' && isCollapsed && (
+        <StatusContainer>
+          <StatusMark />
+          <Text variant="t100" as="p">
+            Purchasable
+          </Text>
+        </StatusContainer>
+      )}
+      <CollapsibleWrapper collapsed={isCollapsed}>
+        <CollapsibleElement>
+          <Content data-size={size}>
+            <NftWidgetContent
+              ownerHandle={ownerHandle}
+              size={size}
+              nftStatus={nftStatus}
+              isOwner={isOwner}
+              needsSettling={needsSettling}
+              onNftPutOnSale={onNftPutOnSale}
+              onNftAcceptBid={onNftAcceptBid}
+              onWithdrawBid={onWithdrawBid}
+              bidFromPreviousAuction={bidFromPreviousAuction}
+              onNftCancelSale={onNftCancelSale}
+              onNftChangePrice={onNftChangePrice}
+              onNftPurchase={onNftPurchase}
+              onNftSettlement={onNftSettlement}
+              onNftBuyNow={onNftBuyNow}
+              userBidCreatedAt={userBidCreatedAt}
+              userBidAmount={userBidAmount}
+            />
+          </Content>
+          <NftHistory size={size} width={width} historyItems={nftHistory} />
+        </CollapsibleElement>
+      </CollapsibleWrapper>
     </Container>
     </Container>
   )
   )
 }
 }

+ 41 - 0
packages/atlas/src/components/_nft/NftWidget/NftWidget.types.ts

@@ -0,0 +1,41 @@
+import BN from 'bn.js'
+
+import { BasicBidFieldsFragment } from '@/api/queries/__generated__/fragments.generated'
+import { EnglishTimerState } from '@/hooks/useNftState'
+
+export type Auction = {
+  status: 'auction'
+  type: 'open' | 'english'
+  startingPrice: BN
+  buyNowPrice: BN | undefined
+  topBid: BasicBidFieldsFragment | undefined
+  topBidAmount: BN | undefined
+  topBidderHandle: string | undefined
+  topBidderAvatarUris: string[] | null | undefined
+  isUserTopBidder: boolean | undefined
+  userBidAmount: BN | undefined
+  userBidUnlockDate: Date | undefined
+  canWithdrawBid: boolean | undefined
+  canChangeBid: boolean | undefined
+  hasTimersLoaded: boolean | undefined
+  englishTimerState: EnglishTimerState | undefined
+  auctionPlannedEndDate: Date | undefined
+  startsAtDate: Date | undefined
+  plannedEndAtBlock: number | null | undefined
+  startsAtBlock: number | null | undefined
+  auctionBeginsInDays: number
+  auctionBeginsInSeconds: number
+  isUserWhitelisted: boolean | undefined
+}
+
+export type NftWidgetStatus =
+  | {
+      status: 'idle'
+      lastSalePrice: BN | undefined
+      lastSaleDate: Date | undefined
+    }
+  | {
+      status: 'buy-now'
+      buyNowPrice: BN
+    }
+  | Auction

+ 54 - 0
packages/atlas/src/components/_nft/NftWidget/NftWidgetContent.styles.ts

@@ -0,0 +1,54 @@
+import styled from '@emotion/styled'
+
+import { cVar, sizes, zIndex } from '@/styles'
+
+export const sizeObj = { small: 'small', medium: 'medium' } as const
+export type Size = keyof typeof sizeObj
+
+export type SizeProps = { 'data-size': keyof typeof sizeObj }
+
+export const ButtonGrid = styled.div<SizeProps & { 'data-two-columns'?: boolean }>`
+  display: grid;
+  gap: ${sizes(4)};
+
+  &[data-size=${sizeObj.small}] {
+    gap: ${sizes(2)};
+  }
+
+  &[data-two-columns='true'] {
+    grid-template-columns: 1fr 1fr;
+  }
+`
+
+export const TopBidderContainer = styled.div`
+  display: flex;
+`
+
+export const TopBidderTokenContainer = styled.div<SizeProps>`
+  display: flex;
+  align-items: center;
+  position: relative;
+  left: -4px;
+  z-index: ${zIndex.overlay};
+
+  &::before {
+    display: inline-block;
+    position: absolute;
+    content: '';
+    width: 28px;
+    height: 28px;
+    background: ${cVar('colorBackgroundMuted')};
+    border-radius: 100%;
+    left: -2px;
+    top: -2px;
+  }
+
+  &[data-size=${sizeObj.small}] {
+    &::before {
+      width: 21px;
+      height: 21px;
+      left: -2.5px;
+      top: 1.5px;
+    }
+  }
+`

+ 542 - 0
packages/atlas/src/components/_nft/NftWidget/NftWidgetContent.tsx

@@ -0,0 +1,542 @@
+import BN from 'bn.js'
+import { differenceInSeconds } from 'date-fns'
+import { FC, memo } from 'react'
+
+import { FullBidFieldsFragment } from '@/api/queries/__generated__/fragments.generated'
+import { SvgAlertsInformative24 } from '@/assets/icons'
+import { Avatar } from '@/components/Avatar'
+import { Banner } from '@/components/Banner'
+import { JoyTokenIcon } from '@/components/JoyTokenIcon'
+import { GridItem } from '@/components/LayoutGrid'
+import { NumberFormat } from '@/components/NumberFormat'
+import { Text } from '@/components/Text'
+import { Button } from '@/components/_buttons/Button'
+import { absoluteRoutes } from '@/config/routes'
+import { useMsTimestamp } from '@/hooks/useMsTimestamp'
+import { useTokenPrice } from '@/providers/joystream/joystream.hooks'
+import { formatDateTime, formatDurationShort, formatTime } from '@/utils/time'
+
+import { NftInfoItem, NftTimerItem } from './NftInfoItem'
+import { OwnerHandle } from './NftWidget.styles'
+import { NftWidgetStatus } from './NftWidget.types'
+import { ButtonGrid, TopBidderContainer, TopBidderTokenContainer } from './NftWidgetContent.styles'
+
+type Size = 'small' | 'medium'
+
+type NftWidgetContentProps = {
+  nftStatus: NftWidgetStatus | undefined
+  ownerHandle: string | null | undefined
+  isOwner: boolean | undefined
+  needsSettling: boolean | undefined
+  onNftPutOnSale?: () => void
+  onNftAcceptBid?: () => void
+  onNftPurchase?: () => void
+  onWithdrawBid?: (bid?: BN, createdAt?: Date) => void
+  bidFromPreviousAuction: FullBidFieldsFragment | undefined
+  onNftSettlement?: () => void
+  onNftBuyNow?: () => void
+  onNftCancelSale?: () => void
+  onNftChangePrice?: () => void
+  userBidCreatedAt?: Date
+  userBidAmount?: BN
+  size: Size
+}
+
+export const NftWidgetContent: FC<NftWidgetContentProps> = memo(
+  ({
+    nftStatus,
+    isOwner,
+    ownerHandle,
+    needsSettling,
+    onNftPutOnSale,
+    onNftAcceptBid,
+    onNftPurchase,
+    onWithdrawBid,
+    bidFromPreviousAuction,
+    onNftSettlement,
+    onNftBuyNow,
+    onNftCancelSale,
+    onNftChangePrice,
+    userBidCreatedAt,
+    size,
+    userBidAmount,
+  }) => {
+    const { convertHapiToUSD, isLoadingPrice } = useTokenPrice()
+    const shouldIgnoreTimestamp = nftStatus?.status === 'auction' && !nftStatus.startsAtDate
+    const timestamp = useMsTimestamp({
+      shouldStop: shouldIgnoreTimestamp,
+    })
+    if (!nftStatus) {
+      return null
+    }
+
+    const contentTextVariant = size === 'small' ? 'h400' : 'h600'
+    const buttonSize = size === 'small' ? 'medium' : 'large'
+    const buttonColumnSpan = size === 'small' ? 1 : 2
+    const timerColumnSpan = size === 'small' ? 1 : 2
+
+    switch (nftStatus.status) {
+      case 'idle':
+        return (
+          <>
+            {nftStatus.lastSalePrice ? (
+              <NftInfoItem
+                size={size}
+                label="Last price"
+                content={
+                  <NumberFormat
+                    as="span"
+                    value={nftStatus.lastSalePrice}
+                    format="short"
+                    variant={contentTextVariant}
+                    icon={<JoyTokenIcon size={size === 'small' ? 16 : 24} variant="silver" />}
+                    color="colorText"
+                    withDenomination
+                  />
+                }
+                secondaryText={nftStatus.lastSaleDate && formatDateTime(nftStatus.lastSaleDate)}
+              />
+            ) : (
+              <NftInfoItem
+                size={size}
+                label="status"
+                content={
+                  <Text as="span" variant={contentTextVariant} color="colorText">
+                    Not for sale
+                  </Text>
+                }
+              />
+            )}
+            {bidFromPreviousAuction && (
+              <>
+                <InfoBanner
+                  size={size}
+                  title="Withdraw your bid"
+                  description="You placed a bid in a previous auction that you can now withdraw to claim back your money."
+                />
+                <WithdrawBidFromPreviousAuction size={size} bidFromPreviousAuction={bidFromPreviousAuction} />
+              </>
+            )}
+            {isOwner && (
+              <GridItem colSpan={buttonColumnSpan}>
+                <Button fullWidth variant="secondary" size={buttonSize} onClick={onNftPutOnSale}>
+                  Start sale of this NFT
+                </Button>
+              </GridItem>
+            )}
+          </>
+        )
+      case 'buy-now':
+        return (
+          <>
+            <BuyNow buyNowPrice={nftStatus.buyNowPrice} size={size} />
+
+            <GridItem colSpan={buttonColumnSpan}>
+              <ButtonGrid data-size={size}>
+                {isOwner ? (
+                  <>
+                    <Button fullWidth variant="secondary" size={buttonSize} onClick={onNftChangePrice}>
+                      Change price
+                    </Button>
+                    <Button fullWidth variant="destructive" size={buttonSize} onClick={onNftCancelSale}>
+                      Remove from sale
+                    </Button>
+                  </>
+                ) : (
+                  <GridItem colSpan={buttonColumnSpan}>
+                    <Button fullWidth size={buttonSize} onClick={onNftPurchase}>
+                      Buy now
+                    </Button>
+                  </GridItem>
+                )}
+                {bidFromPreviousAuction && (
+                  <>
+                    <InfoBanner
+                      size={size}
+                      title="Withdraw your bid"
+                      description="You placed a bid in a previous auction that you can now withdraw to claim back your money."
+                    />
+                    <WithdrawBidFromPreviousAuction
+                      secondary
+                      size={size}
+                      bidFromPreviousAuction={bidFromPreviousAuction}
+                    />
+                  </>
+                )}
+              </ButtonGrid>
+            </GridItem>
+          </>
+        )
+      case 'auction': {
+        const getInfoBannerProps = () => {
+          const hasBids = !nftStatus.topBid?.isCanceled && nftStatus.topBidAmount?.gtn(0)
+          if (nftStatus.type === 'open' && bidFromPreviousAuction) {
+            return {
+              title: 'Withdraw your bid to participate',
+              description:
+                'You placed a bid in a previous auction that you can now withdraw to be able to participate in this auction.',
+            }
+          }
+
+          if (nftStatus.englishTimerState === 'expired' && isOwner && !hasBids) {
+            return {
+              title: 'Auction ended',
+              description: 'This auction has ended and no one placed a bid. You can now remove this NFT from sale.',
+            }
+          }
+          if (nftStatus.englishTimerState === 'expired' && !bidFromPreviousAuction && !hasBids && !isOwner) {
+            return {
+              title: 'Auction ended',
+              description:
+                "This auction has ended and no one placed a bid. We're waiting for the NFT owner to remove this NFT from sale.",
+            }
+          }
+          if (
+            nftStatus.englishTimerState === 'expired' &&
+            !bidFromPreviousAuction &&
+            hasBids &&
+            !isOwner &&
+            !nftStatus.isUserTopBidder
+          ) {
+            return {
+              title: 'Auction ended',
+              description:
+                'We are waiting for this auction to be settled by the auction winner or the current NFT owner.',
+            }
+          }
+          if (nftStatus.englishTimerState === 'expired' && bidFromPreviousAuction) {
+            return {
+              title: 'Withdraw your bid',
+              description: 'You placed a bid in a previous auction that you can now withdraw.',
+            }
+          }
+
+          if (nftStatus.englishTimerState === 'running' && bidFromPreviousAuction) {
+            return {
+              title: 'Withdraw your bid to participate',
+              description:
+                'You placed a bid in a previous auction that you can now withdraw to be able to participate in this auction.',
+            }
+          }
+
+          if (nftStatus.englishTimerState === 'upcoming' && bidFromPreviousAuction) {
+            return {
+              title: 'Withdraw your bid to participate',
+              description:
+                'You placed a bid in a previous auction that you can now withdraw to be able to participate in this upcoming auction.',
+            }
+          }
+
+          if (nftStatus.isUserWhitelisted === false) {
+            return {
+              title: "You're not on the whitelist",
+              description: `This sale is available only to members whitelisted by ${ownerHandle}.`,
+            }
+          }
+
+          return null
+        }
+        const infoBannerProps = getInfoBannerProps()
+
+        const infoTextNode = !!nftStatus.userBidAmount?.gtn(0) && nftStatus.userBidUnlockDate && (
+          <GridItem colSpan={buttonColumnSpan}>
+            {nftStatus.type === 'english' ? (
+              <BidPlacingInfoText />
+            ) : (
+              <Text as="p" variant="t100" color="colorText" align="center">
+                {nftStatus.canWithdrawBid ? `Your last bid: ` : `Your last bid (`}
+                <NumberFormat as="span" value={nftStatus.userBidAmount} format="short" withToken />
+                {nftStatus.canWithdrawBid
+                  ? ''
+                  : `) becomes withdrawable on ${formatDateTime(nftStatus.userBidUnlockDate)}`}
+              </Text>
+            )}
+          </GridItem>
+        )
+
+        const topBidAmountInUsd = nftStatus.topBidAmount && convertHapiToUSD(nftStatus.topBidAmount)
+
+        return (
+          <>
+            {nftStatus.topBidAmount?.gtn(0) && !nftStatus.topBid?.isCanceled ? (
+              <NftInfoItem
+                size={size}
+                label="Top bid"
+                content={
+                  <>
+                    <TopBidderContainer>
+                      <Avatar assetUrls={nftStatus.topBidderAvatarUris} size={24} />
+                      <TopBidderTokenContainer data-size={size}>
+                        <JoyTokenIcon size={size === 'small' ? 16 : 24} variant="silver" />
+                      </TopBidderTokenContainer>
+                    </TopBidderContainer>
+                    <NumberFormat
+                      as="span"
+                      format="short"
+                      value={nftStatus.topBidAmount}
+                      variant={contentTextVariant}
+                    />
+                  </>
+                }
+                secondaryText={
+                  !isLoadingPrice && nftStatus.topBidderHandle ? (
+                    <>
+                      {topBidAmountInUsd ? (
+                        <NumberFormat as="span" color="colorText" format="dollar" value={topBidAmountInUsd} />
+                      ) : null}{' '}
+                      from{' '}
+                      <OwnerHandle to={absoluteRoutes.viewer.member(nftStatus.topBidderHandle)}>
+                        <Text as="span" variant="t100">
+                          {nftStatus.isUserTopBidder ? 'you' : nftStatus.topBidderHandle}
+                        </Text>
+                      </OwnerHandle>
+                    </>
+                  ) : null
+                }
+              />
+            ) : (
+              <NftInfoItem
+                size={size}
+                label="Starting Price"
+                content={
+                  <NumberFormat
+                    as="span"
+                    format="short"
+                    value={nftStatus.startingPrice}
+                    variant={contentTextVariant}
+                    icon={<JoyTokenIcon size={size === 'small' ? 16 : 24} variant="silver" />}
+                    withDenomination
+                  />
+                }
+              />
+            )}
+            <BuyNow buyNowPrice={nftStatus.buyNowPrice} size={size} />
+
+            {nftStatus.englishTimerState === 'expired' && (
+              <GridItem colSpan={timerColumnSpan}>
+                <NftInfoItem
+                  size={size}
+                  label="Auction ended on"
+                  loading={!nftStatus.auctionPlannedEndDate}
+                  content={
+                    nftStatus.auctionPlannedEndDate && (
+                      <Text as="span" variant={contentTextVariant} color="colorText">
+                        {formatDateTime(nftStatus.auctionPlannedEndDate)}
+                      </Text>
+                    )
+                  }
+                />
+              </GridItem>
+            )}
+            {nftStatus.englishTimerState === 'running' && nftStatus?.auctionPlannedEndDate && (
+              <GridItem colSpan={timerColumnSpan}>
+                <NftTimerItem size={size} time={nftStatus.auctionPlannedEndDate} />
+              </GridItem>
+            )}
+            {nftStatus.startsAtBlock && nftStatus.auctionBeginsInSeconds >= 0 && (
+              <GridItem colSpan={timerColumnSpan}>
+                <NftInfoItem
+                  size={size}
+                  label="Auction begins on"
+                  loading={!nftStatus.startsAtDate}
+                  content={
+                    nftStatus.startsAtDate && (
+                      <Text as="span" variant={contentTextVariant} color="colorText">
+                        {nftStatus.auctionBeginsInDays > 1 && formatDateTime(nftStatus.startsAtDate)}
+                        {nftStatus.auctionBeginsInDays === 1 && `Tomorrow at ${formatTime(nftStatus.startsAtDate)}`}
+                        {nftStatus.auctionBeginsInDays < 1 &&
+                          formatDurationShort(differenceInSeconds(nftStatus.startsAtDate, timestamp))}
+                      </Text>
+                    )
+                  }
+                />
+              </GridItem>
+            )}
+
+            {nftStatus.hasTimersLoaded && infoBannerProps && <InfoBanner size={size} {...infoBannerProps} />}
+
+            {nftStatus.hasTimersLoaded && needsSettling && (nftStatus.isUserTopBidder || isOwner) && (
+              <GridItem colSpan={buttonColumnSpan}>
+                <Button fullWidth size={buttonSize} onClick={onNftSettlement}>
+                  Settle auction
+                </Button>
+              </GridItem>
+            )}
+
+            {nftStatus.hasTimersLoaded && bidFromPreviousAuction && (
+              <WithdrawBidFromPreviousAuction size={size} bidFromPreviousAuction={bidFromPreviousAuction} />
+            )}
+
+            {nftStatus.hasTimersLoaded &&
+              !needsSettling &&
+              !bidFromPreviousAuction &&
+              (isOwner
+                ? (nftStatus.type === 'open' ||
+                    // english auction with no bids
+                    !nftStatus.topBidAmount ||
+                    nftStatus.topBid?.isCanceled) && (
+                    <GridItem colSpan={buttonColumnSpan}>
+                      <ButtonGrid data-size={size}>
+                        {nftStatus.type === 'open' && nftStatus.topBid && !nftStatus.topBid?.isCanceled && (
+                          <Button fullWidth size={buttonSize} onClick={onNftAcceptBid}>
+                            Review and accept bid
+                          </Button>
+                        )}
+                        <Button
+                          fullWidth
+                          onClick={onNftCancelSale}
+                          variant={
+                            nftStatus.type === 'open' && !nftStatus.topBid?.isCanceled
+                              ? 'destructive-secondary'
+                              : 'destructive'
+                          }
+                          size={buttonSize}
+                        >
+                          Remove from sale
+                        </Button>
+                      </ButtonGrid>
+                    </GridItem>
+                  )
+                : nftStatus.englishTimerState === 'running' &&
+                  nftStatus.isUserWhitelisted !== false &&
+                  (nftStatus.buyNowPrice?.gtn(0) ? (
+                    <GridItem colSpan={buttonColumnSpan}>
+                      <ButtonGrid data-size={size} data-two-columns={size === 'medium'}>
+                        <Button fullWidth variant="secondary" size={buttonSize} onClick={onNftPurchase}>
+                          {nftStatus.canChangeBid ? 'Change bid' : 'Place bid'}
+                        </Button>
+                        <Button fullWidth size={buttonSize} onClick={onNftBuyNow}>
+                          Buy now
+                        </Button>
+                        {/* second row button */}
+                        {nftStatus.canWithdrawBid && (
+                          <GridItem colSpan={buttonColumnSpan}>
+                            <Button
+                              fullWidth
+                              size={buttonSize}
+                              variant="destructive-secondary"
+                              onClick={() => onWithdrawBid?.(userBidAmount, userBidCreatedAt)}
+                            >
+                              Withdraw bid
+                            </Button>
+                          </GridItem>
+                        )}
+
+                        {infoTextNode}
+                      </ButtonGrid>
+                    </GridItem>
+                  ) : (
+                    <GridItem colSpan={buttonColumnSpan}>
+                      <ButtonGrid data-size={size}>
+                        <GridItem colSpan={buttonColumnSpan}>
+                          <Button fullWidth size={buttonSize} onClick={onNftPurchase}>
+                            {nftStatus.canChangeBid ? 'Change bid' : 'Place bid'}
+                          </Button>
+                        </GridItem>
+                        {nftStatus.canWithdrawBid && (
+                          <GridItem colSpan={buttonColumnSpan}>
+                            <Button
+                              fullWidth
+                              size={buttonSize}
+                              variant="destructive-secondary"
+                              onClick={() => onWithdrawBid?.(userBidAmount, userBidCreatedAt)}
+                            >
+                              Withdraw bid
+                            </Button>
+                          </GridItem>
+                        )}
+                        {infoTextNode}
+                      </ButtonGrid>
+                    </GridItem>
+                  )))}
+          </>
+        )
+      }
+    }
+  }
+)
+
+NftWidgetContent.displayName = 'NftWidgetContent'
+
+const BidPlacingInfoText = () => (
+  <Text as="p" variant="t100" color="colorText" align="center">
+    Placing a bid will withdraw your last bid
+  </Text>
+)
+
+export const BuyNow = memo(({ buyNowPrice, size }: { buyNowPrice?: BN; size: Size }) => {
+  const contentTextVariant = size === 'small' ? 'h400' : 'h600'
+  return buyNowPrice?.gtn(0) ? (
+    <NftInfoItem
+      size={size}
+      label="Buy now"
+      content={
+        <NumberFormat
+          icon={<JoyTokenIcon size={size === 'small' ? 16 : 24} variant="silver" />}
+          withDenomination
+          as="span"
+          value={buyNowPrice}
+          format="short"
+          variant={contentTextVariant}
+        />
+      }
+    />
+  ) : null
+})
+BuyNow.displayName = 'BuyNow'
+
+const InfoBanner = ({ title, description, size }: { title: string; description: string; size: Size }) => {
+  const buttonColumnSpan = size === 'small' ? 1 : 2
+  return (
+    <GridItem colSpan={buttonColumnSpan}>
+      <Banner icon={<SvgAlertsInformative24 />} {...{ title, description }} />
+    </GridItem>
+  )
+}
+
+const WithdrawBidFromPreviousAuction = memo(
+  ({
+    secondary,
+    bidFromPreviousAuction,
+    size,
+    onWithdrawBid,
+  }: {
+    size: Size
+    secondary?: boolean
+    bidFromPreviousAuction: FullBidFieldsFragment | undefined
+    onWithdrawBid?: (bid?: BN, createdAt?: Date) => void
+  }) => {
+    const buttonColumnSpan = size === 'small' ? 1 : 2
+    const buttonSize = size === 'small' ? 'medium' : 'large'
+    return bidFromPreviousAuction ? (
+      <>
+        <GridItem colSpan={buttonColumnSpan}>
+          <Button
+            variant={secondary ? 'secondary' : undefined}
+            fullWidth
+            size={buttonSize}
+            onClick={() =>
+              onWithdrawBid?.(new BN(bidFromPreviousAuction.amount), new Date(bidFromPreviousAuction.createdAt))
+            }
+          >
+            Withdraw last bid
+          </Button>
+          <Text as="p" margin={{ top: 2 }} variant="t100" color="colorText" align="center">
+            You bid{' '}
+            <NumberFormat
+              as="span"
+              value={new BN(bidFromPreviousAuction?.amount)}
+              format="short"
+              variant="t100"
+              color="colorText"
+              withToken
+            />{' '}
+            on {formatDateTime(new Date(bidFromPreviousAuction.createdAt))}
+          </Text>
+        </GridItem>
+      </>
+    ) : null
+  }
+)
+
+WithdrawBidFromPreviousAuction.displayName = 'WithdrawBidFromPreviousAuction'

+ 3 - 3
packages/atlas/src/components/_notifications/NotificationTile/NotificationTile.tsx

@@ -81,7 +81,7 @@ export const NotificationTile: FC<NotificationProps> = ({
   className,
   className,
 }) => {
 }) => {
   const { date, video, member, read } = notification
   const { date, video, member, read } = notification
-  const { url: avatarUrl, isLoadingAsset: isLoadingAvatar } = getMemberAvatar(member)
+  const { urls: avatarUrls, isLoadingAsset: isLoadingAvatar } = getMemberAvatar(member)
 
 
   const formattedDate = useMemo(() => {
   const formattedDate = useMemo(() => {
     const differenceDays = differenceInDays(new Date(), date)
     const differenceDays = differenceInDays(new Date(), date)
@@ -111,7 +111,7 @@ export const NotificationTile: FC<NotificationProps> = ({
           variant="compact"
           variant="compact"
           nodeStart={
           nodeStart={
             member ? (
             member ? (
-              <Avatar size={32} assetUrl={avatarUrl} loading={isLoadingAvatar || loading} />
+              <Avatar size={32} assetUrls={avatarUrls} loading={isLoadingAvatar || loading} />
             ) : (
             ) : (
               <NoActorNotificationAvatar size="small" />
               <NoActorNotificationAvatar size="small" />
             )
             )
@@ -155,7 +155,7 @@ export const NotificationTile: FC<NotificationProps> = ({
       )}
       )}
       <AvatarWrapper>
       <AvatarWrapper>
         {member ? (
         {member ? (
-          <Avatar size={40} assetUrl={avatarUrl} loading={isLoadingAvatar || loading} />
+          <Avatar size={40} assetUrls={avatarUrls} loading={isLoadingAvatar || loading} />
         ) : (
         ) : (
           <NoActorNotificationAvatar size="regular" />
           <NoActorNotificationAvatar size="regular" />
         )}
         )}

+ 14 - 14
packages/atlas/src/components/_overlays/AcceptBidDialog/AcceptBidList.tsx

@@ -7,12 +7,11 @@ import { NumberFormat } from '@/components/NumberFormat'
 import { Text } from '@/components/Text'
 import { Text } from '@/components/Text'
 import { RadioInput } from '@/components/_inputs/RadioInput'
 import { RadioInput } from '@/components/_inputs/RadioInput'
 import { useMediaMatch } from '@/hooks/useMediaMatch'
 import { useMediaMatch } from '@/hooks/useMediaMatch'
-import { hapiBnToTokenNumber } from '@/joystream-lib/utils'
 import { getMemberAvatar } from '@/providers/assets/assets.helpers'
 import { getMemberAvatar } from '@/providers/assets/assets.helpers'
 import { formatDateTime } from '@/utils/time'
 import { formatDateTime } from '@/utils/time'
 
 
 import { Bid, SelectedBid } from './AcceptBidDialog.types'
 import { Bid, SelectedBid } from './AcceptBidDialog.types'
-import { BidRowWrapper, Price, TokenPrice } from './AcceptBidList.styles'
+import { BidRowWrapper, Price } from './AcceptBidList.styles'
 
 
 type BidRowProps = {
 type BidRowProps = {
   selectedBid?: SelectedBid
   selectedBid?: SelectedBid
@@ -43,10 +42,10 @@ export const AcceptBidList: FC<AcceptBidListProps> = ({ items, onSelect, selecte
   )
   )
 }
 }
 
 
-export const BidRow: FC<BidRowProps> = ({ bidder, createdAt, amount, amountUSD, selectedBid, onSelect }) => {
+export const BidRow: FC<BidRowProps> = ({ bidder, createdAt, amount, selectedBid, onSelect }) => {
   const xsMatch = useMediaMatch('xs')
   const xsMatch = useMediaMatch('xs')
   const selected = selectedBid?.bidderId === bidder.id
   const selected = selectedBid?.bidderId === bidder.id
-  const { url, isLoadingAsset } = getMemberAvatar(bidder)
+  const { urls, isLoadingAsset } = getMemberAvatar(bidder)
   return (
   return (
     <BidRowWrapper selected={selected} onClick={() => onSelect?.(bidder.id, amount)}>
     <BidRowWrapper selected={selected} onClick={() => onSelect?.(bidder.id, amount)}>
       <RadioInput
       <RadioInput
@@ -54,7 +53,7 @@ export const BidRow: FC<BidRowProps> = ({ bidder, createdAt, amount, amountUSD,
         value={bidder.id}
         value={bidder.id}
         onChange={() => onSelect?.(bidder.id, amount)}
         onChange={() => onSelect?.(bidder.id, amount)}
       />
       />
-      {xsMatch && <Avatar assetUrl={url} loading={isLoadingAsset} size={40} />}
+      {xsMatch && <Avatar assetUrls={urls} loading={isLoadingAsset} size={40} />}
       <div>
       <div>
         <Text as="p" variant="h300" color={!selected ? 'colorText' : undefined} margin={{ bottom: 1 }}>
         <Text as="p" variant="h300" color={!selected ? 'colorText' : undefined} margin={{ bottom: 1 }}>
           {bidder?.handle}
           {bidder?.handle}
@@ -64,15 +63,16 @@ export const BidRow: FC<BidRowProps> = ({ bidder, createdAt, amount, amountUSD,
         </Text>
         </Text>
       </div>
       </div>
       <Price>
       <Price>
-        <TokenPrice>
-          <JoyTokenIcon variant={selected ? 'regular' : 'gray'} />
-          <Text as="p" variant="h300" margin={{ left: 1 }} color={!selected ? 'colorText' : undefined}>
-            {hapiBnToTokenNumber(amount)}
-          </Text>
-        </TokenPrice>
-        {amountUSD !== null && (
-          <NumberFormat value={amountUSD} format="dollar" as="p" variant="t100" color="colorText" />
-        )}
+        <NumberFormat
+          value={amount}
+          icon={<JoyTokenIcon variant={selected ? 'regular' : 'gray'} />}
+          format="short"
+          as="p"
+          variant="h300"
+          color={!selected ? 'colorText' : undefined}
+          withDenomination
+          denominationAlign="right"
+        />
       </Price>
       </Price>
     </BidRowWrapper>
     </BidRowWrapper>
   )
   )

+ 1 - 1
packages/atlas/src/components/_overlays/ImageCropModal/ImageCropModal.stories.tsx

@@ -85,7 +85,7 @@ const RegularTemplate: StoryFn<ImageCropModalProps> = () => {
   return (
   return (
     <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'start', gap: '24px' }}>
     <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'start', gap: '24px' }}>
       <Avatar
       <Avatar
-        assetUrl={avatarImage?.url}
+        assetUrls={avatarImage?.url ? [avatarImage.url] : undefined}
         editable
         editable
         onClick={() => avatarDialogRef.current?.open(avatarImage?.originalBlob, avatarImage?.cropData, true)}
         onClick={() => avatarDialogRef.current?.open(avatarImage?.originalBlob, avatarImage?.cropData, true)}
         size={88}
         size={88}

+ 6 - 3
packages/atlas/src/components/_overlays/MemberDropdown/MemberDropdown.tsx

@@ -7,6 +7,7 @@ import { useTransition } from 'react-spring'
 import useResizeObserver from 'use-resize-observer'
 import useResizeObserver from 'use-resize-observer'
 
 
 import { absoluteRoutes } from '@/config/routes'
 import { absoluteRoutes } from '@/config/routes'
+import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics'
 import { getMemberAvatar } from '@/providers/assets/assets.helpers'
 import { getMemberAvatar } from '@/providers/assets/assets.helpers'
 import { useSubscribeAccountBalance } from '@/providers/joystream/joystream.hooks'
 import { useSubscribeAccountBalance } from '@/providers/joystream/joystream.hooks'
 import { useUser } from '@/providers/user/user.hooks'
 import { useUser } from '@/providers/user/user.hooks'
@@ -30,11 +31,12 @@ export const MemberDropdown = forwardRef<HTMLDivElement, MemberDropdownProps>(
     const navigate = useNavigate()
     const navigate = useNavigate()
     const { channelId, activeMembership, memberships, signOut, setActiveUser, setSignInModalOpen, membershipsLoading } =
     const { channelId, activeMembership, memberships, signOut, setActiveUser, setSignInModalOpen, membershipsLoading } =
       useUser()
       useUser()
+    const { identifyUser } = useSegmentAnalytics()
     const [showWithdrawDialog, setShowWithdrawDialog] = useState(false)
     const [showWithdrawDialog, setShowWithdrawDialog] = useState(false)
     const [disableScrollDuringAnimation, setDisableScrollDuringAnimation] = useState(false)
     const [disableScrollDuringAnimation, setDisableScrollDuringAnimation] = useState(false)
 
 
     const [showSendDialog, setShowSendDialog] = useState(false)
     const [showSendDialog, setShowSendDialog] = useState(false)
-    const { url: memberAvatarUrl } = getMemberAvatar(activeMembership)
+    const { urls: memberAvatarUrls } = getMemberAvatar(activeMembership)
     const selectedChannel = activeMembership?.channels.find((chanel) => chanel.id === channelId)
     const selectedChannel = activeMembership?.channels.find((chanel) => chanel.id === channelId)
 
 
     const memoizedChannelStateBloatBond = useMemo(() => {
     const memoizedChannelStateBloatBond = useMemo(() => {
@@ -77,13 +79,14 @@ export const MemberDropdown = forwardRef<HTMLDivElement, MemberDropdownProps>(
     const handleMemberChange = useCallback(
     const handleMemberChange = useCallback(
       (memberId: string, accountId: string, channelId: string | null) => {
       (memberId: string, accountId: string, channelId: string | null) => {
         setActiveUser({ accountId, memberId, channelId })
         setActiveUser({ accountId, memberId, channelId })
+        identifyUser(memberId)
         setIsList(false)
         setIsList(false)
 
 
         if (publisher) {
         if (publisher) {
           navigate(absoluteRoutes.studio.index())
           navigate(absoluteRoutes.studio.index())
         }
         }
       },
       },
-      [navigate, publisher, setActiveUser]
+      [identifyUser, navigate, publisher, setActiveUser]
     )
     )
 
 
     const handleAddNewChannel = useCallback(() => {
     const handleAddNewChannel = useCallback(() => {
@@ -144,7 +147,7 @@ export const MemberDropdown = forwardRef<HTMLDivElement, MemberDropdownProps>(
     return (
     return (
       <>
       <>
         <WithdrawFundsDialog
         <WithdrawFundsDialog
-          avatarUrl={memberAvatarUrl}
+          avatarUrls={memberAvatarUrls}
           activeMembership={activeMembership}
           activeMembership={activeMembership}
           show={showWithdrawDialog}
           show={showWithdrawDialog}
           onExitClick={toggleWithdrawDialog}
           onExitClick={toggleWithdrawDialog}

+ 3 - 3
packages/atlas/src/components/_overlays/MemberDropdown/MemberDropdownList.tsx

@@ -68,7 +68,7 @@ export const MemberDropdownList: FC<MemberDropdownListProps> = ({
               <ListItem
               <ListItem
                 key={channel.id}
                 key={channel.id}
                 onClick={() => onChannelChange?.(channel.id)}
                 onClick={() => onChannelChange?.(channel.id)}
-                nodeStart={<Avatar assetUrl={channel.avatarPhoto?.resolvedUrl} size={32} />}
+                nodeStart={<Avatar assetUrls={channel.avatarPhoto?.resolvedUrls} size={32} />}
                 label={channel?.title ?? ''}
                 label={channel?.title ?? ''}
                 caption={channel ? `${channel?.followsNum} followers` : undefined}
                 caption={channel ? `${channel?.followsNum} followers` : undefined}
                 selected={channel.id === channelId}
                 selected={channel.id === channelId}
@@ -97,11 +97,11 @@ type MemberListItemProps = {
   onClick: () => void
   onClick: () => void
 }
 }
 const MemberListItem: FC<MemberListItemProps> = ({ member, selected, onClick }) => {
 const MemberListItem: FC<MemberListItemProps> = ({ member, selected, onClick }) => {
-  const { url, isLoadingAsset } = getMemberAvatar(member)
+  const { urls, isLoadingAsset } = getMemberAvatar(member)
   return (
   return (
     <ListItem
     <ListItem
       onClick={onClick}
       onClick={onClick}
-      nodeStart={<Avatar assetUrl={url} loading={isLoadingAsset} />}
+      nodeStart={<Avatar assetUrls={urls} loading={isLoadingAsset} />}
       label={member.handle ?? ''}
       label={member.handle ?? ''}
       selected={selected}
       selected={selected}
       asButton
       asButton

+ 22 - 10
packages/atlas/src/components/_overlays/MemberDropdown/MemberDropdownNav.tsx

@@ -93,8 +93,8 @@ export const MemberDropdownNav: FC<MemberDropdownNavProps> = ({
 }) => {
 }) => {
   const navigate = useNavigate()
   const navigate = useNavigate()
   const selectedChannel = activeMembership?.channels.find((chanel) => chanel.id === channelId)
   const selectedChannel = activeMembership?.channels.find((chanel) => chanel.id === channelId)
-  const { url: memberAvatarUrl, isLoadingAsset: memberAvatarLoading } = getMemberAvatar(activeMembership)
-  const channelAvatarUrl = selectedChannel?.avatarPhoto?.resolvedUrl
+  const { urls: memberAvatarUrls, isLoadingAsset: memberAvatarLoading } = getMemberAvatar(activeMembership)
+  const channelAvatarUrls = selectedChannel?.avatarPhoto?.resolvedUrls
   const setSignInModalOpen = useUserStore((state) => state.actions.setSignInModalOpen)
   const setSignInModalOpen = useUserStore((state) => state.actions.setSignInModalOpen)
   const memberAvatarWrapperRef = useRef<HTMLButtonElement>(null)
   const memberAvatarWrapperRef = useRef<HTMLButtonElement>(null)
   const channelAvatarWrapperRef = useRef<HTMLButtonElement>(null)
   const channelAvatarWrapperRef = useRef<HTMLButtonElement>(null)
@@ -148,7 +148,7 @@ export const MemberDropdownNav: FC<MemberDropdownNavProps> = ({
                 clickable={false}
                 clickable={false}
                 isDisabled={type === 'channel'}
                 isDisabled={type === 'channel'}
                 size={40}
                 size={40}
-                assetUrl={memberAvatarUrl}
+                assetUrls={memberAvatarUrls}
                 loading={memberAvatarLoading}
                 loading={memberAvatarLoading}
               />
               />
               <StyledIconWrapper size="small" icon={<SvgActionMember />} />
               <StyledIconWrapper size="small" icon={<SvgActionMember />} />
@@ -172,7 +172,7 @@ export const MemberDropdownNav: FC<MemberDropdownNavProps> = ({
                 clickable={false}
                 clickable={false}
                 isDisabled={type === 'member'}
                 isDisabled={type === 'member'}
                 size={40}
                 size={40}
-                assetUrl={channelAvatarUrl}
+                assetUrls={channelAvatarUrls}
                 loading={membershipLoading}
                 loading={membershipLoading}
               >
               >
                 {!hasAtLeastOneChannel ? (
                 {!hasAtLeastOneChannel ? (
@@ -193,10 +193,14 @@ export const MemberDropdownNav: FC<MemberDropdownNavProps> = ({
                       {selectedChannel?.title}
                       {selectedChannel?.title}
                     </MemberHandleText>
                     </MemberHandleText>
                     {channelBalance !== undefined ? (
                     {channelBalance !== undefined ? (
-                      <UserBalance>
-                        <JoyTokenIcon size={16} variant="regular" />
-                        <NumberFormat as="span" variant="t200-strong" value={channelBalance} format="short" />
-                      </UserBalance>
+                      <NumberFormat
+                        icon={<JoyTokenIcon size={16} variant="regular" />}
+                        as="span"
+                        variant="t200-strong"
+                        value={channelBalance}
+                        format="short"
+                        withDenomination
+                      />
                     ) : (
                     ) : (
                       <SkeletonLoader width={30} height={20} />
                       <SkeletonLoader width={30} height={20} />
                     )}
                     )}
@@ -213,14 +217,22 @@ export const MemberDropdownNav: FC<MemberDropdownNavProps> = ({
                     >
                     >
                       {accountBalance !== undefined ? (
                       {accountBalance !== undefined ? (
                         <UserBalance>
                         <UserBalance>
-                          <JoyTokenIcon isNegative={isInDebt} size={16} variant="regular" withoutInformationTooltip />
                           <NumberFormat
                           <NumberFormat
+                            icon={
+                              <JoyTokenIcon
+                                isNegative={isInDebt}
+                                size={16}
+                                variant="regular"
+                                withoutInformationTooltip
+                              />
+                            }
                             withTooltip={false}
                             withTooltip={false}
                             as="span"
                             as="span"
                             variant="t200-strong"
                             variant="t200-strong"
                             value={accountBalance}
                             value={accountBalance}
                             format="short"
                             format="short"
                             isNegative={isInDebt}
                             isNegative={isInDebt}
+                            withDenomination
                           />
                           />
                         </UserBalance>
                         </UserBalance>
                       ) : (
                       ) : (
@@ -264,7 +276,7 @@ export const MemberDropdownNav: FC<MemberDropdownNavProps> = ({
             </TextLink>
             </TextLink>
           </BalanceContainer>
           </BalanceContainer>
         </MemberInfoContainer>
         </MemberInfoContainer>
-        <BlurredBG memberUrl={memberAvatarUrl} channelUrl={channelAvatarUrl} isChannel={type === 'channel'}>
+        <BlurredBG memberUrl={memberAvatarUrls?.[0]} channelUrl={channelAvatarUrls?.[0]} isChannel={type === 'channel'}>
           <Filter />
           <Filter />
         </BlurredBG>
         </BlurredBG>
       </MemberInfoAndBgWrapper>
       </MemberInfoAndBgWrapper>

+ 2 - 2
packages/atlas/src/components/_overlays/SendTransferDialogs/SendFundsDialog.tsx

@@ -247,10 +247,10 @@ type ResolvedAvatarProps = {
   member: BasicMembershipFieldsFragment
   member: BasicMembershipFieldsFragment
 }
 }
 const ResolvedAvatar: FC<ResolvedAvatarProps> = ({ member }) => {
 const ResolvedAvatar: FC<ResolvedAvatarProps> = ({ member }) => {
-  const { url, isLoadingAsset } = getMemberAvatar(member)
+  const { urls, isLoadingAsset } = getMemberAvatar(member)
   return (
   return (
     <Tooltip text={member?.handle} placement="top">
     <Tooltip text={member?.handle} placement="top">
-      <Avatar assetUrl={url} loading={isLoadingAsset} size={24} />
+      <Avatar assetUrls={urls} loading={isLoadingAsset} size={24} />
     </Tooltip>
     </Tooltip>
   )
   )
 }
 }

+ 3 - 3
packages/atlas/src/components/_overlays/SendTransferDialogs/WithdrawFundsDialog.tsx

@@ -32,7 +32,7 @@ type WithdrawFundsDialogProps = {
   show: boolean
   show: boolean
   totalBalance?: BN
   totalBalance?: BN
   channelBalance?: BN
   channelBalance?: BN
-  avatarUrl?: string | null
+  avatarUrls?: string[] | null
   channelId?: string | null
   channelId?: string | null
 }
 }
 
 
@@ -42,7 +42,7 @@ export const WithdrawFundsDialog: FC<WithdrawFundsDialogProps> = ({
   onExitClick,
   onExitClick,
   activeMembership,
   activeMembership,
   show,
   show,
-  avatarUrl,
+  avatarUrls,
   totalBalance = new BN(0),
   totalBalance = new BN(0),
   channelBalance = new BN(0),
   channelBalance = new BN(0),
   channelId,
   channelId,
@@ -186,7 +186,7 @@ export const WithdrawFundsDialog: FC<WithdrawFundsDialogProps> = ({
             Destination account
             Destination account
           </Text>
           </Text>
           <VerticallyCenteredDiv>
           <VerticallyCenteredDiv>
-            <StyledAvatar assetUrl={avatarUrl} />
+            <StyledAvatar assetUrls={avatarUrls} />
             <Text as="span" variant="t100" margin={{ left: 2, right: 1 }}>
             <Text as="span" variant="t100" margin={{ left: 2, right: 1 }}>
               {activeMembership?.handle}
               {activeMembership?.handle}
             </Text>
             </Text>

+ 4 - 2
packages/atlas/src/components/_video/BackgroundVideoPlayer/BackgroundVideoPlayer.styles.ts

@@ -3,6 +3,8 @@ import { css } from '@emotion/react'
 import styled from '@emotion/styled'
 import styled from '@emotion/styled'
 import { Link } from 'react-router-dom'
 import { Link } from 'react-router-dom'
 
 
+import { AssetImage } from '@/components/AssetImage'
+import { AssetVideo } from '@/components/AssetVideo/AssetVideo'
 import { cVar, media, sizes, zIndex } from '@/styles'
 import { cVar, media, sizes, zIndex } from '@/styles'
 
 
 type VideoWrapperProps = {
 type VideoWrapperProps = {
@@ -13,7 +15,7 @@ export const VideoWrapper = styled.div<VideoWrapperProps>`
   overflow: hidden;
   overflow: hidden;
 `
 `
 
 
-export const VideoPoster = styled.img`
+export const VideoPoster = styled(AssetImage)`
   position: absolute;
   position: absolute;
   object-fit: cover;
   object-fit: cover;
   max-height: 100%;
   max-height: 100%;
@@ -29,7 +31,7 @@ export const VideoPoster = styled.img`
   }
   }
 `
 `
 
 
-export const StyledVideo = styled.video`
+export const StyledVideo = styled(AssetVideo)`
   position: absolute;
   position: absolute;
   object-fit: cover;
   object-fit: cover;
   max-height: 100%;
   max-height: 100%;

+ 6 - 4
packages/atlas/src/components/_video/BackgroundVideoPlayer/BackgroundVideoPlayer.tsx

@@ -17,7 +17,9 @@ type BackgroundVideoPlayerProps = {
   videoPlaytime?: number
   videoPlaytime?: number
   videoId?: string
   videoId?: string
   withFade?: boolean
   withFade?: boolean
-} & VideoHTMLAttributes<HTMLVideoElement>
+  src: string[]
+  poster: string[]
+} & Omit<VideoHTMLAttributes<HTMLVideoElement>, 'src' | 'poster'>
 
 
 export const BackgroundVideoPlayer: FC<BackgroundVideoPlayerProps> = ({
 export const BackgroundVideoPlayer: FC<BackgroundVideoPlayerProps> = ({
   autoPlay,
   autoPlay,
@@ -110,13 +112,13 @@ export const BackgroundVideoPlayer: FC<BackgroundVideoPlayerProps> = ({
       {playing && <VideoProgress video={videoRef.current} isPlaying={isPlaying} tick={10} limit={videoPlaytime} />}
       {playing && <VideoProgress video={videoRef.current} isPlaying={isPlaying} tick={10} limit={videoPlaytime} />}
       <StyledLink withFade={withFade} to={videoId ? absoluteRoutes.viewer.video(videoId) : ''}>
       <StyledLink withFade={withFade} to={videoId ? absoluteRoutes.viewer.video(videoId) : ''}>
         <StyledVideo
         <StyledVideo
-          src={src}
+          resolvedVideoUrls={src}
           autoPlay={autoPlay}
           autoPlay={autoPlay}
           playsInline={playsInline}
           playsInline={playsInline}
           ref={videoRef}
           ref={videoRef}
           onEnded={handleEnded}
           onEnded={handleEnded}
           onPlay={handlePlay}
           onPlay={handlePlay}
-          poster={poster}
+          resolvedPosterUrls={poster}
           {...props}
           {...props}
           muted={handleActions ? isMuted : props.muted}
           muted={handleActions ? isMuted : props.muted}
         />
         />
@@ -128,7 +130,7 @@ export const BackgroundVideoPlayer: FC<BackgroundVideoPlayerProps> = ({
             classNames={transitions.names.fade}
             classNames={transitions.names.fade}
             timeout={300}
             timeout={300}
           >
           >
-            <VideoPoster src={poster} alt="" />
+            <VideoPoster resolvedUrls={poster} alt="" />
           </CSSTransition>
           </CSSTransition>
         )}
         )}
       </StyledLink>
       </StyledLink>

+ 2 - 2
packages/atlas/src/components/_video/VideoHero/VideoHero.tsx

@@ -125,9 +125,9 @@ export const VideoHero: FC<VideoHeroProps> = ({
             muted={soundMuted}
             muted={soundMuted}
             autoPlay
             autoPlay
             onTimeUpdate={onTimeUpdate}
             onTimeUpdate={onTimeUpdate}
-            poster={videoHeroData.heroPosterUrl ?? undefined}
+            poster={[videoHeroData.heroPosterUrl ?? '']}
             onEnded={handleEnded}
             onEnded={handleEnded}
-            src={videoHeroData?.heroVideoCutUrl}
+            src={[videoHeroData?.heroVideoCutUrl]}
           />
           />
         )}
         )}
         <GradientOverlay withSolidOverlay />
         <GradientOverlay withSolidOverlay />

+ 3 - 3
packages/atlas/src/components/_video/VideoPlayer/VideoOverlay.tsx

@@ -16,7 +16,7 @@ type VideoOverlayProps = {
   playerState: PlayerState
   playerState: PlayerState
   onPlayAgain: () => void
   onPlayAgain: () => void
   channelId?: string
   channelId?: string
-  currentThumbnailUrl?: string | null
+  currentThumbnailUrls?: string[] | null
   videoId?: string
   videoId?: string
   isFullScreen?: boolean
   isFullScreen?: boolean
   isPlayNextDisabled?: boolean
   isPlayNextDisabled?: boolean
@@ -29,7 +29,7 @@ export const VideoOverlay: FC<VideoOverlayProps> = ({
   playerState,
   playerState,
   onPlayAgain,
   onPlayAgain,
   channelId,
   channelId,
-  currentThumbnailUrl,
+  currentThumbnailUrls,
   videoId,
   videoId,
   isFullScreen,
   isFullScreen,
   isPlayNextDisabled,
   isPlayNextDisabled,
@@ -87,7 +87,7 @@ export const VideoOverlay: FC<VideoOverlayProps> = ({
               isPlayNextDisabled={isPlayNextDisabled}
               isPlayNextDisabled={isPlayNextDisabled}
               onPlayAgain={onPlayAgain}
               onPlayAgain={onPlayAgain}
               channelId={channelId}
               channelId={channelId}
-              currentThumbnailUrl={currentThumbnailUrl}
+              currentThumbnailUrls={currentThumbnailUrls}
               randomNextVideo={playRandomVideoOnEnded ? randomNextVideo : undefined}
               randomNextVideo={playRandomVideoOnEnded ? randomNextVideo : undefined}
             />
             />
           )}
           )}

+ 2 - 1
packages/atlas/src/components/_video/VideoPlayer/VideoOverlays/EndingOverlay.styles.ts

@@ -1,5 +1,6 @@
 import styled from '@emotion/styled'
 import styled from '@emotion/styled'
 
 
+import { AssetImage } from '@/components/AssetImage'
 import { CircularProgress } from '@/components/CircularProgress'
 import { CircularProgress } from '@/components/CircularProgress'
 import { Text } from '@/components/Text'
 import { Text } from '@/components/Text'
 import { Button } from '@/components/_buttons/Button'
 import { Button } from '@/components/_buttons/Button'
@@ -163,7 +164,7 @@ export const RestartButton = styled(Button)`
   }
   }
 `
 `
 
 
-export const VideoThumbnail = styled.img`
+export const VideoThumbnail = styled(AssetImage)`
   width: 320px;
   width: 320px;
   display: none;
   display: none;
 
 

+ 8 - 8
packages/atlas/src/components/_video/VideoPlayer/VideoOverlays/EndingOverlay.tsx

@@ -25,7 +25,7 @@ import {
 
 
 type EndingOverlayProps = {
 type EndingOverlayProps = {
   channelId?: string
   channelId?: string
-  currentThumbnailUrl?: string | null
+  currentThumbnailUrls?: string[] | null
   isFullScreen?: boolean
   isFullScreen?: boolean
   onPlayAgain?: () => void
   onPlayAgain?: () => void
   randomNextVideo?: BasicVideoFieldsFragment | null
   randomNextVideo?: BasicVideoFieldsFragment | null
@@ -39,7 +39,7 @@ export const EndingOverlay: FC<EndingOverlayProps> = ({
   onPlayAgain,
   onPlayAgain,
   isFullScreen,
   isFullScreen,
   channelId,
   channelId,
-  currentThumbnailUrl,
+  currentThumbnailUrls,
   randomNextVideo,
   randomNextVideo,
   isEnded,
   isEnded,
   isPlayNextDisabled,
   isPlayNextDisabled,
@@ -49,7 +49,7 @@ export const EndingOverlay: FC<EndingOverlayProps> = ({
   const [isCountDownStarted, setIsCountDownStarted] = useState(false)
   const [isCountDownStarted, setIsCountDownStarted] = useState(false)
   const mdMatch = useMediaMatch('md')
   const mdMatch = useMediaMatch('md')
 
 
-  const randomNextVideoThumbnailUrl = randomNextVideo?.thumbnailPhoto?.resolvedUrl
+  const randomNextVideoThumbnailUrls = randomNextVideo?.thumbnailPhoto?.resolvedUrls
 
 
   useEffect(() => {
   useEffect(() => {
     if (!randomNextVideo || !isEnded) {
     if (!randomNextVideo || !isEnded) {
@@ -103,13 +103,13 @@ export const EndingOverlay: FC<EndingOverlayProps> = ({
     }
     }
   }
   }
 
 
-  const thumbnailUrl = useMemo(() => {
+  const thumbnailUrls = useMemo(() => {
     if (randomNextVideo) {
     if (randomNextVideo) {
-      return randomNextVideoThumbnailUrl || ''
+      return randomNextVideoThumbnailUrls
     } else {
     } else {
-      return currentThumbnailUrl || ''
+      return currentThumbnailUrls
     }
     }
-  }, [currentThumbnailUrl, randomNextVideo, randomNextVideoThumbnailUrl])
+  }, [currentThumbnailUrls, randomNextVideo, randomNextVideoThumbnailUrls])
 
 
   const stopPropagationx = (e: MouseEvent) => {
   const stopPropagationx = (e: MouseEvent) => {
     e.stopPropagation()
     e.stopPropagation()
@@ -124,7 +124,7 @@ export const EndingOverlay: FC<EndingOverlayProps> = ({
               navigate(absoluteRoutes.viewer.video(randomNextVideo.id))
               navigate(absoluteRoutes.viewer.video(randomNextVideo.id))
             }}
             }}
           >
           >
-            <VideoThumbnail src={thumbnailUrl} />
+            <VideoThumbnail resolvedUrls={thumbnailUrls} />
             <VideoInfo>
             <VideoInfo>
               <Text as="span" variant={mdMatch ? 't300' : 't200'} color="colorText">
               <Text as="span" variant={mdMatch ? 't300' : 't200'} color="colorText">
                 Up next
                 Up next

+ 1 - 1
packages/atlas/src/components/_video/VideoPlayer/VideoPlayer.stories.tsx

@@ -30,7 +30,7 @@ const Template: StoryFn<VideoPlayerProps> = (args) => (
 )
 )
 export const Regular = Template.bind({})
 export const Regular = Template.bind({})
 Regular.args = {
 Regular.args = {
-  src: 'https://eu-central-1.linodeobjects.com/atlas-assets/videos/1.mp4',
+  videoUrls: ['https://eu-central-1.linodeobjects.com/atlas-assets/videos/1.mp4'],
   fill: true,
   fill: true,
 }
 }
 
 

+ 54 - 20
packages/atlas/src/components/_video/VideoPlayer/VideoPlayer.tsx

@@ -20,6 +20,7 @@ import { SvgActionClose, SvgControlsCaptionsOutline, SvgControlsCaptionsSolid }
 import { Avatar } from '@/components/Avatar'
 import { Avatar } from '@/components/Avatar'
 import { absoluteRoutes } from '@/config/routes'
 import { absoluteRoutes } from '@/config/routes'
 import { useMediaMatch } from '@/hooks/useMediaMatch'
 import { useMediaMatch } from '@/hooks/useMediaMatch'
+import { useSegmentAnalytics, videoPlaybackParams } from '@/hooks/useSegmentAnalytics'
 import { usePersonalDataStore } from '@/providers/personalData'
 import { usePersonalDataStore } from '@/providers/personalData'
 import { isMobile } from '@/utils/browser'
 import { isMobile } from '@/utils/browser'
 import { ConsoleLogger, SentryLogger } from '@/utils/logs'
 import { ConsoleLogger, SentryLogger } from '@/utils/logs'
@@ -71,7 +72,7 @@ import { CustomVideojsEvents, PlayerState, VOLUME_STEP, hotkeysHandler, isFullSc
 import { VideoJsConfig, useVideoJsPlayer } from './videoJsPlayer'
 import { VideoJsConfig, useVideoJsPlayer } from './videoJsPlayer'
 
 
 export type VideoPlayerProps = {
 export type VideoPlayerProps = {
-  channelAvatarUrl?: string | null
+  channelAvatarUrls?: string[] | null
   isChannelAvatarLoading?: boolean
   isChannelAvatarLoading?: boolean
   isShareDialogOpen?: boolean
   isShareDialogOpen?: boolean
   onCloseShareDialog?: () => void
   onCloseShareDialog?: () => void
@@ -80,6 +81,7 @@ export type VideoPlayerProps = {
   nextVideo?: FullVideoFieldsFragment | null
   nextVideo?: FullVideoFieldsFragment | null
   className?: string
   className?: string
   videoStyle?: CSSProperties
   videoStyle?: CSSProperties
+  onError?: () => void
   autoplay?: boolean
   autoplay?: boolean
   playing?: boolean
   playing?: boolean
   videoId?: string
   videoId?: string
@@ -106,7 +108,7 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
   {
   {
     isVideoPending,
     isVideoPending,
     className,
     className,
-    channelAvatarUrl,
+    channelAvatarUrls,
     isChannelAvatarLoading,
     isChannelAvatarLoading,
     onCloseShareDialog,
     onCloseShareDialog,
     onAddVideoView,
     onAddVideoView,
@@ -121,6 +123,7 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
     availableTextTracks,
     availableTextTracks,
     isMinimized,
     isMinimized,
     onMinimizedExit,
     onMinimizedExit,
+    onError,
     ...videoJsConfig
     ...videoJsConfig
   },
   },
   externalRef
   externalRef
@@ -131,6 +134,12 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
   const [isSharingOverlayOpen, setIsSharingOverlayOpen] = useState(false)
   const [isSharingOverlayOpen, setIsSharingOverlayOpen] = useState(false)
   const { height: playerHeight = 0 } = useResizeObserver({ box: 'border-box', ref: playerRef })
   const { height: playerHeight = 0 } = useResizeObserver({ box: 'border-box', ref: playerRef })
   const customControlsRef = useRef<HTMLDivElement>(null)
   const customControlsRef = useRef<HTMLDivElement>(null)
+  const {
+    trackVideoPlaybackResumed,
+    trackVideoPlaybackPaused,
+    trackVideoPlaybackStarted,
+    trackVideoPlaybackCompleted,
+  } = useSegmentAnalytics()
 
 
   const customControlsOffset =
   const customControlsOffset =
     ((customControlsRef.current?.getBoundingClientRect().top || 0) -
     ((customControlsRef.current?.getBoundingClientRect().top || 0) -
@@ -175,6 +184,18 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
     )
     )
   }, [availableTextTracks, captionsLanguage, storedLanguageExists])
   }, [availableTextTracks, captionsLanguage, storedLanguageExists])
 
 
+  const videoPlaybackData = useMemo(
+    (): videoPlaybackParams => ({
+      videoId: videoId ?? 'no data',
+      channelId: video?.channel.id ?? 'no data',
+      title: video?.title ?? 'no data',
+      totalLength: video?.duration ?? -1,
+      fullScreen: isFullScreen,
+      quality: video?.mediaMetadata?.pixelHeight?.toString() ?? '1',
+    }),
+    [videoId, video?.channel.id, video?.title, video?.duration, isFullScreen, video?.mediaMetadata?.pixelHeight]
+  )
+
   const playVideo = useCallback(
   const playVideo = useCallback(
     async (player: VideoJsPlayer | null, withIndicator?: boolean, callback?: () => void) => {
     async (player: VideoJsPlayer | null, withIndicator?: boolean, callback?: () => void) => {
       if (!player) {
       if (!player) {
@@ -184,6 +205,9 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
       try {
       try {
         setNeedsManualPlay(false)
         setNeedsManualPlay(false)
         const playPromise = await player.play()
         const playPromise = await player.play()
+        if (playPromise) {
+          trackVideoPlaybackResumed(videoPlaybackData)
+        }
         if (playPromise && callback) callback()
         if (playPromise && callback) callback()
       } catch (error) {
       } catch (error) {
         if (error.name === 'AbortError') {
         if (error.name === 'AbortError') {
@@ -197,22 +221,26 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
           ConsoleLogger.warn('Video playback failed', error)
           ConsoleLogger.warn('Video playback failed', error)
         } else {
         } else {
           SentryLogger.error('Video playback failed', 'VideoPlayer', error, {
           SentryLogger.error('Video playback failed', 'VideoPlayer', error, {
-            video: { id: videoId, url: videoJsConfig.src },
+            video: { id: videoId, urls: videoJsConfig.videoUrls },
           })
           })
         }
         }
       }
       }
     },
     },
-    [videoId, videoJsConfig.src]
+    [trackVideoPlaybackResumed, videoId, videoPlaybackData, videoJsConfig.videoUrls]
   )
   )
 
 
-  const pauseVideo = useCallback((player: VideoJsPlayer | null, withIndicator?: boolean, callback?: () => void) => {
-    if (!player) {
-      return
-    }
-    withIndicator && player.trigger(CustomVideojsEvents.PauseControl)
-    callback?.()
-    player.pause()
-  }, [])
+  const pauseVideo = useCallback(
+    (player: VideoJsPlayer | null, withIndicator?: boolean, callback?: () => void) => {
+      if (!player) {
+        return
+      }
+      withIndicator && player.trigger(CustomVideojsEvents.PauseControl)
+      callback?.()
+      player.pause()
+      trackVideoPlaybackPaused(videoPlaybackData)
+    },
+    [trackVideoPlaybackPaused, videoPlaybackData]
+  )
 
 
   useEffect(() => {
   useEffect(() => {
     if (!isVideoPending) {
     if (!isVideoPending) {
@@ -280,13 +308,14 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
       return
       return
     }
     }
     const handler = () => {
     const handler = () => {
+      onError?.()
       setPlayerState('error')
       setPlayerState('error')
     }
     }
     player.on('error', handler)
     player.on('error', handler)
     return () => {
     return () => {
       player.off('error', handler)
       player.off('error', handler)
     }
     }
-  })
+  }, [onError, player])
 
 
   // handle setting playback rate
   // handle setting playback rate
   useEffect(() => {
   useEffect(() => {
@@ -301,10 +330,11 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
   // When src is null that means something went wrong during asset resolution
   // When src is null that means something went wrong during asset resolution
   // No need to log anything here, error logging is handled in resolvers
   // No need to log anything here, error logging is handled in resolvers
   useEffect(() => {
   useEffect(() => {
-    if (videoJsConfig.src === null) {
+    if (!videoJsConfig.videoUrls) {
       setPlayerState('error')
       setPlayerState('error')
+      onError?.()
     }
     }
-  }, [videoJsConfig.src])
+  }, [onError, videoJsConfig.videoUrls])
 
 
   // handle video loading
   // handle video loading
   useEffect(() => {
   useEffect(() => {
@@ -331,12 +361,13 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
     }
     }
     const handler = () => {
     const handler = () => {
       setPlayerState('ended')
       setPlayerState('ended')
+      trackVideoPlaybackCompleted(videoPlaybackData)
     }
     }
     player.on('ended', handler)
     player.on('ended', handler)
     return () => {
     return () => {
       player.off('ended', handler)
       player.off('ended', handler)
     }
     }
-  }, [nextVideo, player])
+  }, [nextVideo, player, trackVideoPlaybackCompleted, videoPlaybackData])
 
 
   // handle loadstart
   // handle loadstart
   useEffect(() => {
   useEffect(() => {
@@ -363,13 +394,14 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
         .then(() => {
         .then(() => {
           onAddVideoView?.()
           onAddVideoView?.()
           setIsPlaying(true)
           setIsPlaying(true)
+          trackVideoPlaybackStarted(videoPlaybackData)
         })
         })
         .catch((e) => {
         .catch((e) => {
           setNeedsManualPlay(true)
           setNeedsManualPlay(true)
           ConsoleLogger.warn('Video autoplay failed', e)
           ConsoleLogger.warn('Video autoplay failed', e)
         })
         })
     }
     }
-  }, [player, isLoaded, autoplay, onAddVideoView])
+  }, [player, isLoaded, autoplay, onAddVideoView, trackVideoPlaybackStarted, videoPlaybackData])
 
 
   // handle playing and pausing from outside the component
   // handle playing and pausing from outside the component
   useEffect(() => {
   useEffect(() => {
@@ -378,10 +410,12 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
     }
     }
     if (playing) {
     if (playing) {
       playVideo(player)
       playVideo(player)
+      trackVideoPlaybackResumed(videoPlaybackData)
     } else {
     } else {
       player.pause()
       player.pause()
+      trackVideoPlaybackPaused(videoPlaybackData)
     }
     }
-  }, [playVideo, player, playing])
+  }, [playVideo, player, playing, trackVideoPlaybackPaused, trackVideoPlaybackResumed, videoPlaybackData])
 
 
   // handle playing and pausing
   // handle playing and pausing
   useEffect(() => {
   useEffect(() => {
@@ -894,7 +928,7 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
             handlePlayPause(true)
             handlePlayPause(true)
           }}
           }}
           channelId={video?.channel.id}
           channelId={video?.channel.id}
-          currentThumbnailUrl={videoJsConfig.posterUrl}
+          currentThumbnailUrls={videoJsConfig.posterUrls}
           playRandomVideoOnEnded={!isEmbedded}
           playRandomVideoOnEnded={!isEmbedded}
           isMinimized={isMinimized}
           isMinimized={isMinimized}
         />
         />
@@ -906,7 +940,7 @@ const VideoPlayerComponent: ForwardRefRenderFunction<HTMLVideoElement, VideoPlay
                 <Avatar
                 <Avatar
                   clickable
                   clickable
                   size={isFullScreen && !isMobile() ? 88 : 32}
                   size={isFullScreen && !isMobile() ? 88 : 32}
-                  assetUrl={channelAvatarUrl}
+                  assetUrls={channelAvatarUrls}
                   loading={isChannelAvatarLoading}
                   loading={isChannelAvatarLoading}
                 />
                 />
               </a>
               </a>

Some files were not shown because too many files changed in this diff