about summary refs log tree commit diff
path: root/src/state/models/user-autocomplete-view.ts
blob: 8f467da69c90d6eecb82bc0197793ebea1e2e633 (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
import {makeAutoObservable, runInAction} from 'mobx'
import {
  AppBskyGraphGetFollows as GetFollows,
  AppBskyActorSearchTypeahead as SearchTypeahead,
} from '@atproto/api'
import {RootStoreModel} from './root-store'

export class UserAutocompleteViewModel {
  // state
  isLoading = false
  isActive = false
  prefix = ''
  _searchPromise: Promise<any> | undefined

  // data
  follows: GetFollows.Follow[] = []
  searchRes: SearchTypeahead.User[] = []
  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
    this.prefix = prefix.trim()
    if (this.prefix) {
      await this._searchPromise
      if (this.prefix !== origPrefix) {
        return // another prefix was set before we got our chance
      }
      this._searchPromise = this._search()
    } else {
      this.searchRes = []
    }
  }

  // internal
  // =

  private async _getFollows() {
    const res = await this.rootStore.api.app.bsky.graph.getFollows({
      user: this.rootStore.me.did || '',
    })
    runInAction(() => {
      this.follows = res.data.follows
      for (const f of this.follows) {
        this.knownHandles.add(f.handle)
      }
    })
  }

  private async _search() {
    const res = await this.rootStore.api.app.bsky.actor.searchTypeahead({
      term: this.prefix,
      limit: 8,
    })
    runInAction(() => {
      this.searchRes = res.data.users
      for (const u of this.searchRes) {
        this.knownHandles.add(u.handle)
      }
    })
  }
}