get feature list on web
This commit is contained in:
@ -3696,7 +3696,7 @@ export enum UploadImportFileType {
|
||||
export type User = {
|
||||
__typename?: 'User';
|
||||
email?: Maybe<Scalars['String']>;
|
||||
featureList?: Maybe<Array<Maybe<Feature>>>;
|
||||
featureList?: Maybe<Array<Feature>>;
|
||||
features?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
followersCount?: Maybe<Scalars['Int']>;
|
||||
friendsCount?: Maybe<Scalars['Int']>;
|
||||
@ -7140,7 +7140,7 @@ export type UploadImportFileSuccessResolvers<ContextType = ResolverContext, Pare
|
||||
|
||||
export type UserResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User']> = {
|
||||
email?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
featureList?: Resolver<Maybe<Array<Maybe<ResolversTypes['Feature']>>>, ParentType, ContextType>;
|
||||
featureList?: Resolver<Maybe<Array<ResolversTypes['Feature']>>, ParentType, ContextType>;
|
||||
features?: Resolver<Maybe<Array<Maybe<ResolversTypes['String']>>>, ParentType, ContextType>;
|
||||
followersCount?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
|
||||
friendsCount?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
|
||||
|
||||
@ -2984,7 +2984,7 @@ enum UploadImportFileType {
|
||||
|
||||
type User {
|
||||
email: String
|
||||
featureList: [Feature]
|
||||
featureList: [Feature!]
|
||||
features: [String]
|
||||
followersCount: Int
|
||||
friendsCount: Int
|
||||
|
||||
@ -368,6 +368,17 @@ export const functionResolvers = {
|
||||
}
|
||||
return undefined
|
||||
},
|
||||
async featureList(
|
||||
_: User,
|
||||
__: Record<string, unknown>,
|
||||
ctx: WithDataSourcesContext
|
||||
) {
|
||||
if (!ctx.claims?.uid) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return findUserFeatures(ctx.claims.uid)
|
||||
},
|
||||
async features(
|
||||
user: User,
|
||||
__: Record<string, unknown>,
|
||||
@ -376,18 +387,8 @@ export const functionResolvers = {
|
||||
if (!ctx.claims?.uid) {
|
||||
return undefined
|
||||
}
|
||||
const userFeatures = await findUserFeatures(ctx.claims.uid)
|
||||
return userFeatures.map((feature) => feature.name)
|
||||
},
|
||||
async featureList(
|
||||
_: User,
|
||||
__: Record<string, unknown>,
|
||||
ctx: WithDataSourcesContext
|
||||
) {
|
||||
if (!ctx.uid) {
|
||||
return undefined
|
||||
}
|
||||
return findUserFeatures(ctx.uid)
|
||||
|
||||
return (await findUserFeatures(ctx.claims.uid)).map((f) => f.name)
|
||||
},
|
||||
},
|
||||
Article: {
|
||||
|
||||
@ -89,7 +89,7 @@ const schema = gql`
|
||||
source: String
|
||||
intercomHash: String
|
||||
features: [String]
|
||||
featureList: [Feature]
|
||||
featureList: [Feature!]
|
||||
}
|
||||
|
||||
type Profile {
|
||||
|
||||
@ -123,10 +123,8 @@ export const signFeatureToken = (
|
||||
}
|
||||
|
||||
export const findUserFeatures = async (userId: string) => {
|
||||
return getRepository(Feature).find({
|
||||
where: {
|
||||
user: { id: userId },
|
||||
},
|
||||
return getRepository(Feature).findBy({
|
||||
user: { id: userId },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -7,5 +7,10 @@ export const userHasFeature = (
|
||||
if (!user) {
|
||||
return false
|
||||
}
|
||||
return user.features.includes(feature)
|
||||
return user.featureList.some(
|
||||
(f) =>
|
||||
f.name === feature &&
|
||||
f.grantedAt &&
|
||||
(!f.expiresAt || new Date(f.expiresAt) > new Date())
|
||||
)
|
||||
}
|
||||
|
||||
21
packages/web/lib/networking/fragments/featureFragment.ts
Normal file
21
packages/web/lib/networking/fragments/featureFragment.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { gql } from 'graphql-request'
|
||||
|
||||
export const featureFragment = gql`
|
||||
fragment FeatureFields on Feature {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
updatedAt
|
||||
grantedAt
|
||||
expiresAt
|
||||
}
|
||||
`
|
||||
|
||||
export interface Feature {
|
||||
id: string
|
||||
name: string
|
||||
createdAt: Date
|
||||
updatedAt?: Date
|
||||
grantedAt?: Date
|
||||
expiresAt?: Date
|
||||
}
|
||||
@ -1,16 +1,17 @@
|
||||
import { gql } from 'graphql-request'
|
||||
import { Feature, featureFragment } from '../fragments/featureFragment'
|
||||
import { gqlFetcher } from '../networkHelpers'
|
||||
|
||||
export interface OptInFeatureInput {
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface OptInFeatureSuccess {
|
||||
feature: { id: string }
|
||||
export interface OptInFeatureResponse {
|
||||
feature?: Feature
|
||||
}
|
||||
|
||||
interface Response {
|
||||
optInFeature: OptInFeatureSuccess
|
||||
optInFeature: OptInFeatureResponse
|
||||
}
|
||||
|
||||
export async function optInFeature(
|
||||
@ -21,7 +22,7 @@ export async function optInFeature(
|
||||
optInFeature(input: $input) {
|
||||
... on OptInFeatureSuccess {
|
||||
feature {
|
||||
id
|
||||
...FeatureFields
|
||||
}
|
||||
}
|
||||
... on OptInFeatureError {
|
||||
@ -29,17 +30,14 @@ export async function optInFeature(
|
||||
}
|
||||
}
|
||||
}
|
||||
${featureFragment}
|
||||
`
|
||||
try {
|
||||
const data = await gqlFetcher(mutation, {
|
||||
input,
|
||||
})
|
||||
const output = data as Response | undefined
|
||||
if (
|
||||
!output ||
|
||||
!output.optInFeature ||
|
||||
'errorCodes' in output?.optInFeature
|
||||
) {
|
||||
if (!output || !output.optInFeature.feature) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { gql } from 'graphql-request'
|
||||
import useSWR from 'swr'
|
||||
import { Feature, featureFragment } from '../fragments/featureFragment'
|
||||
import { publicGqlFetcher } from '../networkHelpers'
|
||||
|
||||
type ViewerQueryResponse = {
|
||||
@ -22,6 +23,7 @@ export type UserBasicData = {
|
||||
source: string
|
||||
intercomHash: string
|
||||
features: string[]
|
||||
featureList: Feature[]
|
||||
}
|
||||
|
||||
export type UserProfile = {
|
||||
@ -48,8 +50,12 @@ export function useGetViewerQuery(): ViewerQueryResponse {
|
||||
source
|
||||
intercomHash
|
||||
features
|
||||
featureList {
|
||||
...FeatureFields
|
||||
}
|
||||
}
|
||||
}
|
||||
${featureFragment}
|
||||
`
|
||||
|
||||
const { data, error, mutate } = useSWR(query, publicGqlFetcher)
|
||||
|
||||
@ -6,6 +6,7 @@ import { HStack, VStack } from '../../../components/elements/LayoutPrimitives'
|
||||
import { StyledText } from '../../../components/elements/StyledText'
|
||||
import { SettingsLayout } from '../../../components/templates/SettingsLayout'
|
||||
import { styled } from '../../../components/tokens/stitches.config'
|
||||
import { userHasFeature } from '../../../lib/featureFlag'
|
||||
import { optInFeature } from '../../../lib/networking/mutations/optIntoFeatureMutation'
|
||||
import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
|
||||
import { applyStoredTheme } from '../../../lib/themeUpdater'
|
||||
@ -43,13 +44,11 @@ export default function Account(): JSX.Element {
|
||||
)
|
||||
|
||||
const hasYouTube = useMemo(() => {
|
||||
return (
|
||||
(viewerData?.me?.features.indexOf('youtube-transcripts') ?? -1) !== -1
|
||||
)
|
||||
return userHasFeature(viewerData?.me, 'youtube-transcripts')
|
||||
}, [viewerData])
|
||||
|
||||
const hasNotion = useMemo(() => {
|
||||
return (viewerData?.me?.features.indexOf('notion') ?? -1) !== -1
|
||||
return userHasFeature(viewerData?.me, 'notion')
|
||||
}, [viewerData])
|
||||
|
||||
applyStoredTheme()
|
||||
|
||||
Reference in New Issue
Block a user