useCheckEntitlements.ts135 lines · main
1import { useCallback, useMemo } from 'react'
2
3import { useSelectedOrganizationQuery } from './useSelectedOrganization'
4import type {
5 Entitlement,
6 EntitlementConfig,
7 EntitlementType,
8 FeatureKey,
9} from '@/data/entitlements/entitlements-query'
10import { useEntitlementsQuery } from '@/data/entitlements/entitlements-query'
11import { IS_PLATFORM } from '@/lib/constants'
12
13function isNumericConfig(
14 _config: EntitlementConfig,
15 type: EntitlementType
16): _config is { enabled: boolean; unlimited: boolean; value: number } {
17 return type === 'numeric'
18}
19
20function isSetConfig(
21 _config: EntitlementConfig,
22 type: EntitlementType
23): _config is { enabled: boolean; set: string[] } {
24 return type === 'set'
25}
26
27function getEntitlementNumericValue(entitlement: Entitlement | null): number | undefined {
28 const entitlementConfig = entitlement?.config
29 return entitlementConfig &&
30 entitlement.type &&
31 isNumericConfig(entitlementConfig, entitlement.type)
32 ? entitlementConfig.value
33 : undefined
34}
35
36function isEntitlementUnlimited(entitlement: Entitlement | null): boolean {
37 const entitlementConfig = entitlement?.config
38 return entitlementConfig &&
39 entitlement.type &&
40 isNumericConfig(entitlementConfig, entitlement.type)
41 ? entitlementConfig.unlimited
42 : false
43}
44
45function getEntitlementSetValues(entitlement: Entitlement | null): string[] {
46 const entitlementConfig = entitlement?.config
47 return entitlementConfig && entitlement.type && isSetConfig(entitlementConfig, entitlement.type)
48 ? entitlementConfig.set
49 : []
50}
51
52function getEntitlementMax(entitlement: Entitlement | null): number | undefined {
53 return isEntitlementUnlimited(entitlement)
54 ? Number.MAX_SAFE_INTEGER
55 : getEntitlementNumericValue(entitlement)
56}
57
58export function useHasEntitlementAccess(organizationSlug?: string) {
59 const shouldGetSelectedOrg = !organizationSlug
60 const { data: selectedOrg } = useSelectedOrganizationQuery({
61 enabled: shouldGetSelectedOrg,
62 })
63
64 const finalOrgSlug = organizationSlug || selectedOrg?.slug
65 const enabled = IS_PLATFORM && !!finalOrgSlug
66
67 const { data: entitlementsData } = useEntitlementsQuery({ slug: finalOrgSlug! }, { enabled })
68
69 return useCallback(
70 (key: string) =>
71 IS_PLATFORM
72 ? (entitlementsData?.entitlements.find((e) => e.feature.key === key)?.hasAccess ?? false)
73 : true,
74 [entitlementsData]
75 )
76}
77
78export function useCheckEntitlements(
79 featureKey: FeatureKey,
80 organizationSlug?: string,
81 options?: {
82 enabled?: boolean
83 }
84) {
85 // If no organizationSlug provided, try to get it from the selected organization
86 const shouldGetSelectedOrg = !organizationSlug && options?.enabled !== false
87 const {
88 data: selectedOrg,
89 isPending: isLoadingSelectedOrg,
90 isSuccess: isSuccessSelectedOrg,
91 } = useSelectedOrganizationQuery({
92 enabled: shouldGetSelectedOrg,
93 })
94
95 const finalOrgSlug = organizationSlug || selectedOrg?.slug
96 const enabled = IS_PLATFORM ? options?.enabled !== false && !!finalOrgSlug : false
97
98 const {
99 data: entitlementsData,
100 isPending: isLoadingEntitlements,
101 isSuccess: isSuccessEntitlements,
102 } = useEntitlementsQuery({ slug: finalOrgSlug! }, { enabled })
103
104 const { entitlement } = useMemo((): {
105 entitlement: Entitlement | null
106 } => {
107 // If no organization slug, no access
108 if (!finalOrgSlug) return { entitlement: null }
109
110 const entitlement = entitlementsData?.entitlements.find(
111 (entitlement) => entitlement.feature.key === featureKey
112 )
113
114 return {
115 entitlement: entitlement ?? null,
116 }
117 }, [entitlementsData, featureKey, finalOrgSlug])
118
119 const isLoading = shouldGetSelectedOrg
120 ? isLoadingSelectedOrg || isLoadingEntitlements
121 : isLoadingEntitlements
122 const isSuccess = shouldGetSelectedOrg
123 ? isSuccessSelectedOrg && isSuccessEntitlements
124 : isSuccessEntitlements
125
126 return {
127 hasAccess: IS_PLATFORM ? (entitlement?.hasAccess ?? false) : true,
128 isLoading: IS_PLATFORM ? isLoading : false,
129 isSuccess: IS_PLATFORM ? isSuccess : true,
130 getEntitlementNumericValue: () => getEntitlementNumericValue(entitlement),
131 isEntitlementUnlimited: () => isEntitlementUnlimited(entitlement),
132 getEntitlementSetValues: () => getEntitlementSetValues(entitlement),
133 getEntitlementMax: () => getEntitlementMax(entitlement),
134 }
135}