11import firebaseApp from "firebase" ;
22import { getDatabase , onValue , ref } from "firebase/database" ;
33import { doc , getFirestore , onSnapshot } from "firebase/firestore" ;
4- import { useEffect , useState } from "react" ;
4+ import { useEffect , useMemo , useState } from "react" ;
55import { useSelector } from "react-redux" ;
66import { getUserAuthDetails } from "store/slices/global/user/selectors" ;
7+ import { isPremiumUser } from "utils/PremiumUtils" ;
78
89export enum BlockType {
910 GRR = "grr" ,
1011 COMPLIANCE_ISSUE = "compliance-issue" ,
12+ // Free / unlicensed users at a gated domain (e.g. aon.com). Used with metadata.exemptBrowserstackUsers
13+ // so users holding an active BrowserStack seat pass through while everyone else sees the access screen.
14+ ACCESS_DENIED = "access-denied" ,
1115}
1216
17+ type BlockConfigValue = {
18+ isBlocked : boolean ;
19+ reason ?: string ;
20+ // metadata.exemptBrowserstackUsers (boolean): when true, users who hold an active BrowserStack-provisioned
21+ // seat are NOT blocked (e.g. block free users at a domain but let BrowserStack-licensed users through).
22+ // Omit for a full domain block (everyone at the domain is blocked).
23+ metadata ?: Record < string , any > ;
24+ } ;
25+
1326export type BlockConfig = {
14- [ key in BlockType ] ?: {
15- isBlocked : boolean ;
16- reason ?: string ;
17- metadata ?: Record < string , any > ;
18- } ;
27+ [ key in BlockType ] ?: BlockConfigValue ;
28+ } ;
29+
30+ /**
31+ * A user has an active BrowserStack seat when their subscription is BrowserStack-provisioned and currently active.
32+ */
33+ const hasActiveBrowserstackSeat = ( planDetails : any ) : boolean => {
34+ return Boolean ( planDetails ?. subscription ?. isBrowserstackSubscription ) && isPremiumUser ( planDetails ) ;
35+ } ;
36+
37+ /**
38+ * A domain block is skipped for BrowserStack-licensed users when metadata.exemptBrowserstackUsers is set.
39+ * Used only for domain-level blocks; explicit per-user blocks always apply.
40+ */
41+ const isUserExemptFromBlock = ( value : BlockConfigValue | undefined , hasBrowserstackSeat : boolean ) : boolean => {
42+ return Boolean ( value ?. metadata ?. exemptBrowserstackUsers ) && hasBrowserstackSeat ;
1943} ;
2044
2145export const useIsUserBlocked = ( ) => {
2246 const user = useSelector ( getUserAuthDetails ) ;
2347 const isLoggedIn = user ?. loggedIn ;
2448 const uid = user ?. details ?. profile ?. uid ;
2549 const email = user ?. details ?. profile ?. email ;
50+ const planDetails = user ?. details ?. planDetails ;
51+
52+ const hasBrowserstackSeat = useMemo (
53+ ( ) => hasActiveBrowserstackSeat ( planDetails ) ,
54+ // eslint-disable-next-line react-hooks/exhaustive-deps
55+ [ planDetails ?. planId , planDetails ?. status , planDetails ?. subscription ?. endDate , planDetails ?. subscription ?. isBrowserstackSubscription ]
56+ ) ;
2657
2758 const [ domainBlockConfig , setDomainBlockConfig ] = useState < BlockConfig | undefined > ( undefined ) ;
2859 const [ userBlockConfig , setUserBlockConfig ] = useState < BlockConfig | undefined > ( undefined ) ;
@@ -77,8 +108,7 @@ export const useIsUserBlocked = () => {
77108 return ;
78109 }
79110
80- // console.log({ userBlockConfig, domainBlockConfig });
81-
111+ // Explicit per-user blocks always apply, regardless of plan.
82112 for ( const [ key , value ] of Object . entries ( userBlockConfig || { } ) ) {
83113 if ( value ?. isBlocked ) {
84114 setFinalBlockConfig ( {
@@ -90,8 +120,10 @@ export const useIsUserBlocked = () => {
90120 }
91121 }
92122
123+ // Domain-level blocks can exempt BrowserStack-licensed users via metadata.exemptBrowserstackUsers,
124+ // so free users at a domain are blocked while users with a BrowserStack seat pass through.
93125 for ( const [ key , value ] of Object . entries ( domainBlockConfig || { } ) ) {
94- if ( value ?. isBlocked ) {
126+ if ( value ?. isBlocked && ! isUserExemptFromBlock ( value , hasBrowserstackSeat ) ) {
95127 setFinalBlockConfig ( {
96128 [ key ] : {
97129 ...value ,
@@ -100,7 +132,10 @@ export const useIsUserBlocked = () => {
100132 return ;
101133 }
102134 }
103- } , [ domainBlockConfig , isLoggedIn , uid , userBlockConfig ] ) ;
135+
136+ // No applicable block (or user is exempt) — clear any stale block config.
137+ setFinalBlockConfig ( undefined ) ;
138+ } , [ domainBlockConfig , isLoggedIn , uid , userBlockConfig , hasBrowserstackSeat ] ) ;
104139
105140 return {
106141 isBlocked : ! ! finalBlockConfig && Object . values ( finalBlockConfig ) . some ( ( value ) => value . isBlocked ) ,
0 commit comments