فهرست منبع

Channel view details (#1019)

* channel details

* unfollow dialog

* details

* typo
Diego Cardenas 3 سال پیش
والد
کامیت
0f50b5c952

+ 27 - 0
src/api/client/resolvers.ts

@@ -17,6 +17,8 @@ import {
   TransformOrionFollowsField,
   TransformOrionViewsField,
 } from './transforms'
+import { ORION_CHANNEL_VIEWS_QUERY_NAME, TransformOrionChannelViewsField } from './transforms/orionViews'
+import { RemoveQueryNodeChannelViewsField } from './transforms/queryNodeViews'
 
 import { Channel, ChannelEdge, Video, VideoEdge } from '../queries'
 
@@ -84,6 +86,7 @@ export const queryNodeStitchingResolvers = (
     // channel queries
     channelByUniqueInput: createResolverWithTransforms(queryNodeSchema, 'channelByUniqueInput', [
       RemoveQueryNodeFollowsField,
+      RemoveQueryNodeChannelViewsField,
     ]),
     channels: async (parent, args, context, info) => {
       try {
@@ -117,6 +120,7 @@ export const queryNodeStitchingResolvers = (
     },
     channelsConnection: createResolverWithTransforms(queryNodeSchema, 'channelsConnection', [
       RemoveQueryNodeFollowsField,
+      RemoveQueryNodeChannelViewsField,
     ]),
     // mixed queries
     search: createResolverWithTransforms(queryNodeSchema, 'search', [
@@ -181,6 +185,29 @@ export const queryNodeStitchingResolvers = (
     },
   },
   Channel: {
+    views: async (parent, args, context, info) => {
+      if (parent.views != null) {
+        return parent.views
+      }
+      try {
+        return await delegateToSchema({
+          schema: orionSchema,
+          operation: 'query',
+          // operationName has to be manually kept in sync with the query name used
+          operationName: 'GetChannelViews',
+          fieldName: ORION_CHANNEL_VIEWS_QUERY_NAME,
+          args: {
+            channelId: parent.id,
+          },
+          context,
+          info,
+          transforms: [TransformOrionChannelViewsField],
+        })
+      } catch (error) {
+        Logger.warn('Failed to resolve views field', { error })
+        return null
+      }
+    },
     follows: async (parent, args, context, info) => {
       if (parent.follows !== undefined) {
         return parent.follows

+ 42 - 0
src/api/client/transforms/orionViews.ts

@@ -112,3 +112,45 @@ export const TransformBatchedOrionViewsField: Transform = {
     return result
   },
 }
+
+export const ORION_CHANNEL_VIEWS_QUERY_NAME = 'channelViews'
+export const TransformOrionChannelViewsField: Transform = {
+  transformRequest(request) {
+    request.document = {
+      ...request.document,
+      definitions: request.document.definitions.map((definition) => {
+        if (definition.kind === 'OperationDefinition') {
+          return {
+            ...definition,
+            selectionSet: {
+              ...definition.selectionSet,
+              selections: definition.selectionSet.selections.map((selection) => {
+                if (selection.kind === 'Field' && selection.name.value === ORION_CHANNEL_VIEWS_QUERY_NAME) {
+                  return {
+                    ...selection,
+                    selectionSet: VIDEO_INFO_SELECTION_SET,
+                  }
+                }
+                return selection
+              }),
+            },
+          }
+        }
+        return definition
+      }),
+    }
+
+    return request
+  },
+  transformResult(result) {
+    if (result.errors) {
+      throw new OrionError(result.errors)
+    }
+
+    const views = result?.data?.[ORION_CHANNEL_VIEWS_QUERY_NAME]?.views || 0
+    const data = {
+      channelViews: views,
+    }
+    return { data }
+  },
+}

+ 24 - 0
src/api/client/transforms/queryNodeViews.ts

@@ -23,3 +23,27 @@ export const RemoveQueryNodeViewsField: Transform = {
     return request
   },
 }
+
+// remove views field from the query node video request
+export const RemoveQueryNodeChannelViewsField: Transform = {
+  transformRequest: (request) => {
+    request.document = {
+      ...request.document,
+      definitions: request.document.definitions.map((definition) => {
+        if (definition.kind === 'FragmentDefinition' && definition.name.value === 'AllChannelFields') {
+          return {
+            ...definition,
+            selectionSet: {
+              ...definition.selectionSet,
+              selections: definition.selectionSet.selections.filter((selection) => {
+                return selection.kind !== 'Field' || selection.name.value !== 'views'
+              }),
+            },
+          }
+        }
+        return definition
+      }),
+    }
+    return request
+  },
+}

+ 1 - 0
src/api/queries/__generated__/baseTypes.generated.ts

@@ -115,6 +115,7 @@ export type Channel = {
   avatarPhotoUrls: Array<Scalars['String']>
   avatarPhotoAvailability: AssetAvailability
   follows?: Maybe<Scalars['Int']>
+  views?: Maybe<Scalars['Int']>
 }
 
 export type ChannelWhereInput = {

+ 55 - 0
src/api/queries/__generated__/channels.generated.tsx

@@ -19,11 +19,13 @@ export type AllChannelFieldsFragment = {
   __typename?: 'Channel'
   description?: Types.Maybe<string>
   follows?: Types.Maybe<number>
+  views?: Types.Maybe<number>
   isPublic?: Types.Maybe<boolean>
   isCensored: boolean
   coverPhotoUrls: Array<string>
   coverPhotoAvailability: Types.AssetAvailability
   language?: Types.Maybe<{ __typename?: 'Language'; iso: string }>
+  ownerMember?: Types.Maybe<{ __typename?: 'Membership'; id: string; handle: string; avatarUri?: Types.Maybe<string> }>
   coverPhotoDataObject?: Types.Maybe<{ __typename?: 'DataObject' } & DataObjectFieldsFragment>
 } & BasicChannelFieldsFragment
 
@@ -103,6 +105,15 @@ export type GetBatchedChannelFollowsQuery = {
   batchedChannelFollows: Array<Types.Maybe<{ __typename?: 'ChannelFollowsInfo'; id: string; follows: number }>>
 }
 
+export type GetChannelViewsQueryVariables = Types.Exact<{
+  channelId: Types.Scalars['ID']
+}>
+
+export type GetChannelViewsQuery = {
+  __typename?: 'Query'
+  channelViews?: Types.Maybe<{ __typename?: 'EntityViewsInfo'; id: string; views: number }>
+}
+
 export type FollowChannelMutationVariables = Types.Exact<{
   channelId: Types.Scalars['ID']
 }>
@@ -139,11 +150,17 @@ export const AllChannelFieldsFragmentDoc = gql`
     ...BasicChannelFields
     description
     follows
+    views
     isPublic
     isCensored
     language {
       iso
     }
+    ownerMember {
+      id
+      handle
+      avatarUri
+    }
     coverPhotoUrls
     coverPhotoAvailability
     coverPhotoDataObject {
@@ -454,6 +471,44 @@ export type GetBatchedChannelFollowsQueryResult = Apollo.QueryResult<
   GetBatchedChannelFollowsQuery,
   GetBatchedChannelFollowsQueryVariables
 >
+export const GetChannelViewsDocument = gql`
+  query GetChannelViews($channelId: ID!) {
+    channelViews(channelId: $channelId) {
+      id
+      views
+    }
+  }
+`
+
+/**
+ * __useGetChannelViewsQuery__
+ *
+ * To run a query within a React component, call `useGetChannelViewsQuery` and pass it any options that fit your needs.
+ * When your component renders, `useGetChannelViewsQuery` returns an object from Apollo Client that contains loading, error, and data properties
+ * you can use to render your UI.
+ *
+ * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
+ *
+ * @example
+ * const { data, loading, error } = useGetChannelViewsQuery({
+ *   variables: {
+ *      channelId: // value for 'channelId'
+ *   },
+ * });
+ */
+export function useGetChannelViewsQuery(
+  baseOptions: Apollo.QueryHookOptions<GetChannelViewsQuery, GetChannelViewsQueryVariables>
+) {
+  return Apollo.useQuery<GetChannelViewsQuery, GetChannelViewsQueryVariables>(GetChannelViewsDocument, baseOptions)
+}
+export function useGetChannelViewsLazyQuery(
+  baseOptions?: Apollo.LazyQueryHookOptions<GetChannelViewsQuery, GetChannelViewsQueryVariables>
+) {
+  return Apollo.useLazyQuery<GetChannelViewsQuery, GetChannelViewsQueryVariables>(GetChannelViewsDocument, baseOptions)
+}
+export type GetChannelViewsQueryHookResult = ReturnType<typeof useGetChannelViewsQuery>
+export type GetChannelViewsLazyQueryHookResult = ReturnType<typeof useGetChannelViewsLazyQuery>
+export type GetChannelViewsQueryResult = Apollo.QueryResult<GetChannelViewsQuery, GetChannelViewsQueryVariables>
 export const FollowChannelDocument = gql`
   mutation FollowChannel($channelId: ID!) {
     followChannel(channelId: $channelId) {

+ 13 - 1
src/api/queries/channels.graphql

@@ -14,12 +14,17 @@ fragment AllChannelFields on Channel {
   ...BasicChannelFields
   description
   follows
+  views
   isPublic
   isCensored
   language {
     iso
   }
-
+  ownerMember {
+    id
+    handle
+    avatarUri
+  }
   coverPhotoUrls
   coverPhotoAvailability
   coverPhotoDataObject {
@@ -83,6 +88,13 @@ query GetBatchedChannelFollows($channelIdList: [ID!]!) {
     follows
   }
 }
+# modyfying this query name will need a sync-up in `src/api/client/resolvers.ts`
+query GetChannelViews($channelId: ID!) {
+  channelViews(channelId: $channelId) {
+    id
+    views
+  }
+}
 
 mutation FollowChannel($channelId: ID!) {
   followChannel(channelId: $channelId) {

+ 1 - 0
src/api/schemas/extendedQueryNode.graphql

@@ -110,6 +110,7 @@ type Channel {
 
   # === extended from Orion ===
   follows: Int
+  views: Int
 }
 
 input ChannelWhereInput {

+ 4 - 3
src/views/viewer/ChannelView/ChannelAbout.tsx

@@ -4,6 +4,7 @@ import { useParams } from 'react-router'
 import { useChannel, useChannelVideoCount } from '@/api/hooks'
 import { languages } from '@/config/languages'
 import { Text } from '@/shared/components'
+import { formatNumberShort } from '@/utils/number'
 import { formatDate } from '@/utils/time'
 
 import {
@@ -40,8 +41,8 @@ export const ChannelAbout = () => {
             Owned by member
           </Text>
           <AvatarContainer>
-            <StyledAvatar assetUrl={undefined} />
-            <Text variant="body1">placeholder</Text>
+            <StyledAvatar assetUrl={channel?.ownerMember?.avatarUri} />
+            <Text variant="body1">{channel?.ownerMember?.handle}</Text>
           </AvatarContainer>
         </Details>
 
@@ -56,7 +57,7 @@ export const ChannelAbout = () => {
           <Text variant="caption" secondary>
             Num. of views
           </Text>
-          <Text variant="body1">7 245 345</Text>
+          <Text variant="body1">{channel?.views ? formatNumberShort(channel.views) : ''}</Text>
         </Details>
 
         <Details>