forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 💫
1import {useMemo} from 'react'
2import {useMutation, useQueryClient} from '@tanstack/react-query'
3
4import {preferencesQueryKey} from '#/state/queries/preferences'
5import {useAgent, useSession} from '#/state/session'
6import {usePatchAgeAssuranceOtherRequiredData} from '#/ageAssurance'
7import {isUnderAge, maybeRestrictChatSettings} from '#/ageAssurance/util'
8import {IS_DEV} from '#/env'
9import {account} from '#/storage'
10import {pdsAgent} from './session/agent'
11
12// 6s in dev, 48h in prod
13const BIRTHDATE_DELAY_HOURS = IS_DEV ? 0.001 : 48
14
15/**
16 * Stores the timestamp of the birthday update locally. This is used to
17 * debounce birthday updates globally.
18 *
19 * Use {@link useIsBirthdateUpdateAllowed} to check if an update is allowed.
20 */
21export function snoozeBirthdateUpdateAllowedForDid(did: string) {
22 account.set([did, 'birthdateLastUpdatedAt'], new Date().toISOString())
23}
24
25/**
26 * Checks if we've already snoozed bday updates. In some cases, if one is
27 * present, we don't need to set another, such as in AA when reading initial
28 * data on load.
29 */
30export function hasSnoozedBirthdateUpdateForDid(did: string) {
31 return !!account.get([did, 'birthdateLastUpdatedAt'])
32}
33
34/**
35 * Returns whether a birthdate update is currently allowed, based on the
36 * last update timestamp stored locally.
37 */
38export function useIsBirthdateUpdateAllowed() {
39 const {currentAccount} = useSession()
40 return useMemo(() => {
41 if (!currentAccount) return false
42 const lastUpdated = account.get([
43 currentAccount.did,
44 'birthdateLastUpdatedAt',
45 ])
46 if (!lastUpdated) return true
47 const lastUpdatedDate = new Date(lastUpdated)
48 // eslint-disable-next-line react-hooks/purity
49 const diffMs = Date.now() - lastUpdatedDate.getTime()
50 const diffHours = diffMs / (1000 * 60 * 60)
51 return diffHours >= BIRTHDATE_DELAY_HOURS
52 }, [currentAccount])
53}
54
55export function useBirthdateMutation() {
56 const queryClient = useQueryClient()
57 const agent = useAgent()
58 const patchOtherRequiredData = usePatchAgeAssuranceOtherRequiredData()
59
60 return useMutation<void, unknown, {birthDate: Date}>({
61 mutationFn: async ({birthDate}: {birthDate: Date}) => {
62 const bday = birthDate.toISOString()
63 await pdsAgent(agent).setPersonalDetails({birthDate: bday})
64 // triggers a refetch
65 await queryClient.invalidateQueries({
66 queryKey: preferencesQueryKey,
67 })
68
69 if (isUnderAge(birthDate.toISOString(), 18)) {
70 maybeRestrictChatSettings({agent})
71 }
72
73 /**
74 * Also patch the age assurance other required data with the new
75 * birthdate, which may change the user's age assurance access level.
76 */
77 void patchOtherRequiredData({birthdate: bday})
78 snoozeBirthdateUpdateAllowedForDid(agent.sessionManager.did!)
79 },
80 })
81}