Bluesky app fork with some witchin' additions 馃挮
at main 100 lines 3.2 kB view raw
1import {useEffect, useMemo, useState} from 'react' 2import {computeAgeAssuranceRegionAccess} from '@atproto/api' 3 4import {useSession} from '#/state/session' 5import {useAgeAssuranceDataContext} from '#/ageAssurance/data' 6import {logger} from '#/ageAssurance/logger' 7import { 8 AgeAssuranceAccess, 9 type AgeAssuranceState, 10 AgeAssuranceStatus, 11 parseAccessFromString, 12 parseStatusFromString, 13} from '#/ageAssurance/types' 14import {getAgeAssuranceRegionConfigWithFallback} from '#/ageAssurance/util' 15import {useGeolocation} from '#/geolocation' 16 17export function useAgeAssuranceState(): AgeAssuranceState { 18 const {hasSession} = useSession() 19 const geolocation = useGeolocation() 20 const {config, state, data} = useAgeAssuranceDataContext() 21 22 return useMemo(() => { 23 /** 24 * This is where we control logged-out moderation prefs. It's all 25 * downstream of AA now. 26 */ 27 if (!hasSession) 28 return { 29 status: AgeAssuranceStatus.Unknown, 30 access: AgeAssuranceAccess.Safe, 31 } 32 33 // should never happen, but need to guard 34 if (!config) { 35 logger.warn('useAgeAssuranceState: missing config') 36 return { 37 status: AgeAssuranceStatus.Unknown, 38 access: AgeAssuranceAccess.Unknown, 39 } 40 } 41 42 const region = getAgeAssuranceRegionConfigWithFallback(config, geolocation) 43 const isAARequired = region.countryCode !== '*' 44 const isTerminalState = 45 state?.status === 'assured' || state?.status === 'blocked' 46 47 /* 48 * If we are in a terminal state and AA is required for this region, 49 * we can trust the server state completely and avoid recomputing. 50 */ 51 if (isTerminalState && isAARequired) { 52 return { 53 lastInitiatedAt: state.lastInitiatedAt, 54 status: parseStatusFromString(state.status), 55 access: parseAccessFromString(state.access), 56 } 57 } 58 59 /* 60 * Otherwise, we need to compute the access based on the latest data. For 61 * accounts with an accurate birthdate, our default fallback rules should 62 * ensure correct access. 63 */ 64 const result = computeAgeAssuranceRegionAccess(region, data) 65 const computed = { 66 lastInitiatedAt: state?.lastInitiatedAt, 67 // prefer server state 68 status: state?.status 69 ? parseStatusFromString(state?.status) 70 : AgeAssuranceStatus.Unknown, 71 // prefer server state 72 access: result 73 ? parseAccessFromString(result.access) 74 : AgeAssuranceAccess.Full, 75 } 76 logger.debug('debug useAgeAssuranceState', { 77 region, 78 state, 79 data, 80 computed, 81 }) 82 return computed 83 }, [hasSession, geolocation, config, state, data]) 84} 85 86export function useOnAgeAssuranceAccessUpdate( 87 cb: (state: AgeAssuranceState) => void, 88) { 89 const state = useAgeAssuranceState() 90 // start with null to ensure callback is called on first render 91 const [prevAccess, setPrevAccess] = useState<AgeAssuranceAccess | null>(null) 92 93 useEffect(() => { 94 if (prevAccess !== state.access) { 95 setPrevAccess(state.access) 96 cb(state) 97 logger.debug(`useOnAgeAssuranceAccessUpdate`, {state}) 98 } 99 }, [cb, state, prevAccess]) 100}