Преглед изворни кода

Add discover channels section to channel view (#1124)

* Add discover channels section to channel view

* Sort infinite component results

* Implement sorting from useInfiniteGrid
Rafał Pawłow пре 3 година
родитељ
комит
f79a9c2c36

+ 46 - 13
src/api/hooks/channel.ts

@@ -10,6 +10,8 @@ import {
   GetChannelsQueryVariables,
   GetMostFollowedChannelsAllTimeQuery,
   GetMostFollowedChannelsAllTimeQueryVariables,
+  GetMostFollowedChannelsQuery,
+  GetMostFollowedChannelsQueryVariables,
   GetMostViewedChannelsAllTimeQuery,
   GetMostViewedChannelsAllTimeQueryVariables,
   GetMostViewedChannelsQuery,
@@ -21,6 +23,7 @@ import {
   useGetChannelQuery,
   useGetChannelsQuery,
   useGetMostFollowedChannelsAllTimeQuery,
+  useGetMostFollowedChannelsQuery,
   useGetMostViewedChannelsAllTimeQuery,
   useGetMostViewedChannelsQuery,
   useGetVideoCountQuery,
@@ -133,10 +136,45 @@ export const useUnfollowChannel = (opts?: UnfollowChannelOpts) => {
   }
 }
 
-type MostPopularChannelsOpts = QueryHookOptions<GetMostViewedChannelsQuery>
+type MostFollowedChannelsOpts = QueryHookOptions<GetMostFollowedChannelsQuery>
+export const useMostFollowedChannelsIds = (
+  variables?: GetMostFollowedChannelsQueryVariables,
+  opts?: MostFollowedChannelsOpts
+) => {
+  const { data, ...rest } = useGetMostFollowedChannelsQuery({ ...opts, variables })
+  return {
+    mostFollowedChannels: data?.mostFollowedChannels,
+    ...rest,
+  }
+}
+
+export const useMostFollowedChannels = (
+  variables?: GetMostFollowedChannelsQueryVariables,
+  opts?: MostFollowedChannelsOpts
+) => {
+  const { mostFollowedChannels } = useMostFollowedChannelsIds(variables, opts)
+
+  const mostFollowedChannelsIds = mostFollowedChannels?.map((item) => item.id)
+
+  const { channels, ...rest } = useChannels(
+    {
+      where: {
+        id_in: mostFollowedChannelsIds,
+      },
+    },
+    { skip: !mostFollowedChannelsIds }
+  )
+
+  return {
+    channels,
+    ...rest,
+  }
+}
+
+type MostViewedChannelsOpts = QueryHookOptions<GetMostViewedChannelsQuery>
 export const useMostViewedChannelsIds = (
   variables?: GetMostViewedChannelsQueryVariables,
-  opts?: MostPopularChannelsOpts
+  opts?: MostViewedChannelsOpts
 ) => {
   const { data, ...rest } = useGetMostViewedChannelsQuery({ ...opts, variables })
   return {
@@ -147,16 +185,11 @@ export const useMostViewedChannelsIds = (
 
 export const useMostViewedChannels = (
   variables?: GetMostViewedChannelsQueryVariables,
-  opts?: MostPopularChannelsOpts
+  opts?: MostViewedChannelsOpts
 ) => {
   const { mostViewedChannels } = useMostViewedChannelsIds(variables, opts)
 
-  const mostViewedChannelsIds = useMemo(() => {
-    if (mostViewedChannels) {
-      return mostViewedChannels.map((item) => item.id)
-    }
-    return null
-  }, [mostViewedChannels])
+  const mostViewedChannelsIds = mostViewedChannels?.map((item) => item.id)
 
   const { channels, ...rest } = useChannels(
     {
@@ -194,7 +227,7 @@ export const useMostFollowedChannelsAllTimeIds = (
 
 export const useMostFollowedChannelsAllTime = (
   variables?: GetMostFollowedChannelsAllTimeQueryVariables,
-  opts?: MostPopularChannelsOpts
+  opts?: MostFollowedChannelsAllTimeOpts
 ) => {
   const { mostFollowedChannelsAllTime } = useMostFollowedChannelsAllTimeIds(variables, opts)
 
@@ -222,10 +255,10 @@ export const useMostFollowedChannelsAllTime = (
   }
 }
 
-type MostPopularChannelsAllTimeOpts = QueryHookOptions<GetMostViewedChannelsAllTimeQuery>
+type MostViewedChannelsAllTimeOpts = QueryHookOptions<GetMostViewedChannelsAllTimeQuery>
 export const useMostViewedChannelsAllTimeIds = (
   variables?: GetMostViewedChannelsAllTimeQueryVariables,
-  opts?: MostPopularChannelsAllTimeOpts
+  opts?: MostViewedChannelsAllTimeOpts
 ) => {
   const { data, ...rest } = useGetMostViewedChannelsAllTimeQuery({ ...opts, variables })
   return {
@@ -236,7 +269,7 @@ export const useMostViewedChannelsAllTimeIds = (
 
 export const useMostViewedChannelsAllTime = (
   variables?: GetMostViewedChannelsAllTimeQueryVariables,
-  opts?: MostPopularChannelsOpts
+  opts?: MostViewedChannelsAllTimeOpts
 ) => {
   const { mostViewedChannelsAllTime } = useMostViewedChannelsAllTimeIds(variables, opts)
 

+ 3 - 12
src/api/queries/__generated__/baseTypes.generated.ts

@@ -306,16 +306,11 @@ export type Query = {
   mostFollowedChannels: Array<ChannelFollowsInfo>
   /** Get list of most followed channels of all time */
   mostFollowedChannelsAllTime?: Maybe<Array<ChannelFollowsInfo>>
-  /**
-   * Get list of channels with most views in given period
-   * Get most viewed list of categories
-   */
+  /** Get most viewed list of categories */
   mostViewedCategories?: Maybe<Array<EntityViewsInfo>>
-  /** Get most viewed list of categories of all time */
-  mostViewedCategoriesAllTime?: Maybe<Array<EntityViewsInfo>>
-  /** Get most viewed list of channels */
-  mostViewedChannels?: Maybe<Array<EntityViewsInfo>>
   /** Get list of channels with most views in given period */
+  mostViewedChannels?: Maybe<Array<EntityViewsInfo>>
+  /** Get list of channels with most views of all time */
   mostViewedChannelsAllTime?: Maybe<Array<EntityViewsInfo>>
   /** Get most viewed list of videos */
   mostViewedVideos?: Maybe<Array<EntityViewsInfo>>
@@ -399,10 +394,6 @@ export type QueryMostViewedCategoriesArgs = {
   period: Scalars['Int']
 }
 
-export type QueryMostViewedCategoriesAllTimeArgs = {
-  limit: Scalars['Int']
-}
-
 export type QueryMostViewedChannelsArgs = {
   limit?: Maybe<Scalars['Int']>
   period: Scalars['Int']

+ 2 - 8
src/api/schemas/orion.graphql

@@ -67,23 +67,17 @@ type Query {
   mostFollowedChannelsAllTime(limit: Int!): [ChannelFollowsInfo!]
 
   """
-  Get list of channels with most views in given period
   Get most viewed list of categories
   """
   mostViewedCategories(limit: Int, period: Int!): [EntityViewsInfo!]
 
   """
-  Get most viewed list of categories of all time
-  """
-  mostViewedCategoriesAllTime(limit: Int!): [EntityViewsInfo!]
-
-  """
-  Get most viewed list of channels
+  Get list of channels with most views in given period
   """
   mostViewedChannels(limit: Int, period: Int!): [EntityViewsInfo!]
 
   """
-  Get list of channels with most views in given period
+  Get list of channels with most views of all time
   """
   mostViewedChannelsAllTime(limit: Int!): [EntityViewsInfo!]
 

+ 35 - 0
src/components/DiscoverChannels.tsx

@@ -0,0 +1,35 @@
+import styled from '@emotion/styled'
+import React from 'react'
+
+import { ChannelEdge, VideoEdge } from '@/api/queries'
+import { InfiniteChannelWithVideosGrid } from '@/components/InfiniteGrids'
+import { sizes } from '@/shared/theme'
+
+export const DiscoverChannels: React.FC = () => {
+  const sortChannelsByFollowsDesc = (edges?: ChannelEdge[] | VideoEdge[]) => {
+    if (!edges) {
+      return []
+    }
+    return [...edges].sort((a, b) => {
+      if ('follows' in b.node && 'follows' in a.node) {
+        return (b.node.follows || 0) - (a.node.follows || 0)
+      } else {
+        return 0
+      }
+    })
+  }
+
+  return (
+    <StyledInfiniteChannelWithVideosGrid
+      title="Discover channels"
+      onDemand
+      additionalSortFn={sortChannelsByFollowsDesc}
+    />
+  )
+}
+
+const StyledInfiniteChannelWithVideosGrid = styled(InfiniteChannelWithVideosGrid)`
+  :not(:last-of-type) {
+    margin-bottom: ${sizes(38)};
+  }
+`

+ 5 - 4
src/components/InfiniteGrids/InfiniteChannelWithVideosGrid.tsx

@@ -27,7 +27,6 @@ import {
 
 type InfiniteChannelWithVideosGridProps = {
   onDemand?: boolean
-  sortByViews?: boolean
   title?: string
   skipCount?: number
   first?: number
@@ -40,6 +39,7 @@ type InfiniteChannelWithVideosGridProps = {
     name: string
     url: string
   }
+  maximumCount?: number
   additionalSortFn?: (edge?: ChannelEdge[] | VideoEdge[]) => (ChannelEdge | VideoEdge)[]
 }
 
@@ -54,10 +54,10 @@ export const InfiniteChannelWithVideosGrid: FC<InfiniteChannelWithVideosGridProp
   first,
   orderBy = ChannelOrderByInput.CreatedAtAsc,
   className,
-  sortByViews,
   languageSelector,
   idIn = null,
   additionalLink,
+  maximumCount,
   additionalSortFn,
 }) => {
   const [selectedLanguage, setSelectedLanguage] = useState<string | null | undefined>(null)
@@ -91,7 +91,6 @@ export const InfiniteChannelWithVideosGrid: FC<InfiniteChannelWithVideosGridProp
     targetRowsCount,
     dataAccessor: (rawData) => rawData?.channelsConnection,
     itemsPerRow: INITIAL_CHANNELS_PER_ROW,
-    sortByViews,
     additionalSortFn,
   })
 
@@ -100,7 +99,9 @@ export const InfiniteChannelWithVideosGrid: FC<InfiniteChannelWithVideosGridProp
   }
 
   const placeholderItems = Array.from({ length: placeholdersCount }, () => ({ id: undefined }))
-  const shouldShowLoadMoreButton = onDemand && !loading && displayedItems.length < totalCount
+  const shouldShowLoadMoreButton =
+    onDemand && !loading && (displayedItems.length < totalCount || (maximumCount && totalCount < maximumCount))
+
   const itemsToShow = [...displayedItems, ...placeholderItems]
 
   const mappedLanguages = useMemo(() => {

+ 1 - 3
src/components/InfiniteGrids/useInfiniteGrid.ts

@@ -42,7 +42,6 @@ type UseInfiniteGridParams<TRawData, TPaginatedData extends PaginatedData<unknow
   onDemand?: boolean
   onScrollToBottom?: () => void
   orderBy?: ChannelOrderByInput
-  sortByViews?: boolean
   additionalSortFn?: (edge?: ChannelEdge[] | VideoEdge[]) => (ChannelEdge | VideoEdge)[]
 }
 
@@ -70,7 +69,6 @@ export const useInfiniteGrid = <
   onError,
   queryVariables,
   onDemand,
-  sortByViews,
   orderBy = ChannelOrderByInput.CreatedAtDesc,
   additionalSortFn,
 }: UseInfiniteGridParams<TRawData, TPaginatedData, TArgs>): UseInfiniteGridReturn<TPaginatedData> => {
@@ -85,7 +83,7 @@ export const useInfiniteGrid = <
     variables: {
       ...queryVariables,
       orderBy,
-      first: sortByViews ? 100 : targetDisplayedItemsCount,
+      first: additionalSortFn ? 100 : targetDisplayedItemsCount,
     },
     onError,
   })

+ 0 - 1
src/components/PromisingNewChannels.tsx

@@ -26,7 +26,6 @@ export const PromisingNewChannels = () => {
         url: absoluteRoutes.viewer.channels(),
       }}
       additionalSortFn={sortChannelsByViewsDesc}
-      sortByViews
     />
   )
 }

+ 1 - 0
src/components/index.ts

@@ -27,3 +27,4 @@ export * from './OfficialJoystreamUpdate'
 export * from './TopTenThisWeek'
 export * from './TopTenChannels'
 export * from './ChannelWithVideos'
+export * from './DiscoverChannels'

+ 6 - 3
src/views/viewer/ChannelsView/ChannelsView.tsx

@@ -1,7 +1,7 @@
 import styled from '@emotion/styled'
 import React from 'react'
 
-import { InfiniteChannelWithVideosGrid, TopTenChannels, ViewWrapper } from '@/components'
+import { DiscoverChannels, InfiniteChannelWithVideosGrid, TopTenChannels, ViewWrapper } from '@/components'
 import { absoluteRoutes } from '@/config/routes'
 import { CallToActionButton, CallToActionWrapper, Text } from '@/shared/components'
 import { SvgNavHome, SvgNavNew, SvgNavPopular } from '@/shared/icons'
@@ -12,7 +12,8 @@ export const ChannelsView = () => {
     <StyledViewWrapper>
       <Header variant="h2">Browse channels</Header>
       <TopTenChannels />
-      <StyledInfiniteChannelWithVideosGrid title="Channels in your language:" languageSelector onDemand />
+      <DiscoverChannels />
+      <StyledInfiniteChannelWithVideosGrid title="Channels in your language" languageSelector onDemand />
       <CallToActionWrapper>
         <CallToActionButton
           label="Popular on Joystream"
@@ -46,5 +47,7 @@ const StyledViewWrapper = styled(ViewWrapper)`
 `
 
 const StyledInfiniteChannelWithVideosGrid = styled(InfiniteChannelWithVideosGrid)`
-  margin-top: ${sizes(36)};
+  :not(:last-of-type) {
+    margin-bottom: ${sizes(38)};
+  }
 `