mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {useMemo} from 'react'
2import {
3 type $Typed,
4 type AppBskyActorDefs,
5 AppBskyEmbedExternal,
6} from '@atproto/api'
7import {isAfter, parseISO} from 'date-fns'
8
9import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
10import {useLiveNowConfig} from '#/state/service-config'
11import {useTickEveryMinute} from '#/state/shell'
12import type * as bsky from '#/types/bsky'
13
14export function useActorStatus(actor?: bsky.profile.AnyProfileView) {
15 const shadowed = useMaybeProfileShadow(actor)
16 const tick = useTickEveryMinute()
17 const config = useLiveNowConfig()
18
19 return useMemo(() => {
20 tick! // revalidate every minute
21
22 if (
23 shadowed &&
24 'status' in shadowed &&
25 shadowed.status &&
26 validateStatus(shadowed.did, shadowed.status, config) &&
27 isStatusStillActive(shadowed.status.expiresAt)
28 ) {
29 return {
30 isActive: true,
31 status: 'app.bsky.actor.status#live',
32 embed: shadowed.status.embed as $Typed<AppBskyEmbedExternal.View>, // temp_isStatusValid asserts this
33 expiresAt: shadowed.status.expiresAt!, // isStatusStillActive asserts this
34 record: shadowed.status.record,
35 } satisfies AppBskyActorDefs.StatusView
36 } else {
37 return {
38 status: '',
39 isActive: false,
40 record: {},
41 } satisfies AppBskyActorDefs.StatusView
42 }
43 }, [shadowed, config, tick])
44}
45
46export function isStatusStillActive(timeStr: string | undefined) {
47 if (!timeStr) return false
48 const now = new Date()
49 const expiry = parseISO(timeStr)
50
51 return isAfter(expiry, now)
52}
53
54export function validateStatus(
55 did: string,
56 status: AppBskyActorDefs.StatusView,
57 config: {did: string; domains: string[]}[],
58) {
59 if (status.status !== 'app.bsky.actor.status#live') return false
60 const sources = config.find(cfg => cfg.did === did)
61 if (!sources) {
62 return false
63 }
64 try {
65 if (AppBskyEmbedExternal.isView(status.embed)) {
66 const url = new URL(status.embed.external.uri)
67 return sources.domains.includes(url.hostname)
68 } else {
69 return false
70 }
71 } catch {
72 return false
73 }
74}