about summary refs log tree commit diff
path: root/src/state/models/user-autocomplete-view.ts
blob: ad89bb08b872fe346dd615b2657f8692841914c1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import {makeAutoObservable, runInAction} from 'mobx'
import {AppBskyActorDefs} from '@atproto/api'
import AwaitLock from 'await-lock'
import {RootStoreModel} from './root-store'

export class UserAutocompleteViewModel {
  // state
  isLoading = false
  isActive = false
  prefix = ''
  lock = new AwaitLock()

  // data
  follows: AppBskyActorDefs.ProfileViewBasic[] = []
  searchRes: AppBskyActorDefs.ProfileViewBasic[] = []
  knownHandles: Set<string> = new Set()

  constructor(public rootStore: RootStoreModel) {
    makeAutoObservable(
      this,
      {
        rootStore: false,
        knownHandles: false,
      },
      {autoBind: true},
    )
  }

  get suggestions() {
    if (!this.isActive) {
      return []
    }
    if (this.prefix) {
      return this.searchRes.map(user => ({
        handle: user.handle,
        displayName: user.displayName,
        avatar: user.avatar,
      }))
    }
    return this.follows.map(follow => ({
      handle: follow.handle,
      displayName: follow.displayName,
      avatar: follow.avatar,
    }))
  }

  // public api
  // =

  async setup() {
    await this._getFollows()
  }

  setActive(v: boolean) {
    this.isActive = v
  }

  async setPrefix(prefix: string) {
    const origPrefix = prefix.trim()
    this.prefix = origPrefix
    await this.lock.acquireAsync()
    try {
      if (this.prefix) {
        if (this.prefix !== origPrefix) {
          return // another prefix was set before we got our chance
        }
        await this._search()
      } else {
        this.searchRes = []
      }
    } finally {
      this.lock.release()
    }
  }

  // internal
  // =

  async _getFollows() {
    const res = await this.rootStore.agent.getFollows({
      actor: this.rootStore.me.did || '',
    })
    runInAction(() => {
      this.follows = res.data.follows
      for (const f of this.follows) {
        this.knownHandles.add(f.handle)
      }
    })
  }

  async _search() {
    const res = await this.rootStore.agent.searchActorsTypeahead({
      term: this.prefix,
      limit: 8,
    })
    runInAction(() => {
      this.searchRes = res.data.actors
      for (const u of this.searchRes) {
        this.knownHandles.add(u.handle)
      }
    })
  }
}