Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
117
fork

Configure Feed

Select the types of activity you want to include in your feed.

at a876aae44ea07494ebea9727350aa060b81f317b 111 lines 3.6 kB view raw
1import {useMemo} from 'react' 2import { 3 ageAssuranceRuleIDs as ids, 4 type AppBskyAgeassuranceDefs, 5 getAgeAssuranceRegionConfig, 6 type ModerationPrefs, 7} from '@atproto/api' 8 9import {getAge} from '#/lib/strings/time' 10import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation' 11import {useAgeAssuranceDataContext} from '#/ageAssurance/data' 12import {AgeAssuranceAccess} from '#/ageAssurance/types' 13import {type Geolocation, useGeolocation} from '#/geolocation' 14 15export const MIN_ACCESS_AGE = 1 16const FALLBACK_REGION_CONFIG: AppBskyAgeassuranceDefs.ConfigRegion = { 17 countryCode: '*', 18 regionCode: undefined, 19 minAccessAge: MIN_ACCESS_AGE, 20 rules: [ 21 { 22 $type: ids.IfDeclaredOverAge, 23 age: MIN_ACCESS_AGE, 24 access: AgeAssuranceAccess.Full, 25 }, 26 { 27 $type: ids.Default, 28 access: AgeAssuranceAccess.None, 29 }, 30 ], 31} 32 33/** 34 * Get age assurance region config based on geolocation, with fallback to 35 * app defaults if no region config is found. 36 * 37 * See {@link getAgeAssuranceRegionConfig} for the generic option, which can 38 * return undefined if the geolocation does not match any AA region. 39 */ 40export function getAgeAssuranceRegionConfigWithFallback( 41 config: AppBskyAgeassuranceDefs.Config, 42 geolocation: Geolocation, 43): AppBskyAgeassuranceDefs.ConfigRegion { 44 const region = getAgeAssuranceRegionConfig(config, { 45 countryCode: geolocation.countryCode ?? '', 46 regionCode: geolocation.regionCode, 47 }) 48 49 return region || FALLBACK_REGION_CONFIG 50} 51 52/** 53 * Hook to get the age assurance region config based on current geolocation. 54 * Does not fall-back to our app defaults. If no config is found, returns 55 * undefined, which indicates no regional age assurance rules apply. 56 */ 57export function useAgeAssuranceRegionConfig() { 58 const geolocation = useGeolocation() 59 const {config} = useAgeAssuranceDataContext() 60 return useMemo(() => { 61 if (!config) return 62 // use generic helper, we want to potentially return undefined 63 return getAgeAssuranceRegionConfig(config, { 64 countryCode: geolocation.countryCode ?? '', 65 regionCode: geolocation.regionCode, 66 }) 67 }, [config, geolocation]) 68} 69 70/** 71 * Hook to get the age assurance region config based on current geolocation. 72 * Falls back to our app defaults if no region config is found. 73 */ 74export function useAgeAssuranceRegionConfigWithFallback() { 75 return useAgeAssuranceRegionConfig() || FALLBACK_REGION_CONFIG 76} 77 78/** 79 * Some users may have erroneously set their birth date to the current date 80 * if one wasn't set on their account. We previously didn't do validation on 81 * the bday dialog, and it defaulted to the current date. This bug _has_ been 82 * seen in production, so we need to check for it where possible. 83 */ 84export function isLegacyBirthdateBug(birthDate: string) { 85 return ['2025', '2024', '2023'].includes((birthDate || '').slice(0, 4)) 86} 87 88/** 89 * Returns whether the date (converted to an age as a whole integer) is under 90 * the provided minimum age. 91 */ 92export function isUnderAge(birthDate: string, age: number) { 93 return getAge(new Date(birthDate)) < age 94} 95 96export function getBirthdateStringFromAge(age: number) { 97 const today = new Date() 98 return new Date( 99 today.getFullYear() - age, 100 today.getMonth(), 101 today.getDate() - 1, // set to day before to ensure age is reached 102 ).toISOString() 103} 104 105export const makeAgeRestrictedModerationPrefs = ( 106 prefs: ModerationPrefs, 107): ModerationPrefs => ({ 108 ...prefs, 109 adultContentEnabled: false, 110 labels: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES, 111})