diff options
author | Paul Frazee <pfrazee@gmail.com> | 2022-11-17 14:35:12 -0600 |
---|---|---|
committer | Paul Frazee <pfrazee@gmail.com> | 2022-11-17 14:35:12 -0600 |
commit | 2b98714548d585ff14dd09252233144f48b5f4b7 (patch) | |
tree | f200f39732aad5f7da3b554f02d5f78ce96bee12 /src/state/models/user-autocomplete-view.ts | |
parent | 859087f21d148d52d707b0057458e7dd2cbbea0a (diff) | |
download | voidsky-2b98714548d585ff14dd09252233144f48b5f4b7.tar.zst |
Add live search to autocomplete and only highlight known handles
Diffstat (limited to 'src/state/models/user-autocomplete-view.ts')
-rw-r--r-- | src/state/models/user-autocomplete-view.ts | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/state/models/user-autocomplete-view.ts b/src/state/models/user-autocomplete-view.ts new file mode 100644 index 000000000..3d53e5db7 --- /dev/null +++ b/src/state/models/user-autocomplete-view.ts @@ -0,0 +1,97 @@ +import {makeAutoObservable, runInAction} from 'mobx' +import * as GetFollows from '../../third-party/api/src/client/types/app/bsky/graph/getFollows' +import * as SearchTypeahead from '../../third-party/api/src/client/types/app/bsky/actor/searchTypeahead' +import {RootStoreModel} from './root-store' + +export class UserAutocompleteViewModel { + // state + isLoading = false + isActive = false + prefix = '' + _searchPromise: Promise<any> | undefined + + // data + follows: GetFollows.OutputSchema['follows'] = [] + searchRes: SearchTypeahead.OutputSchema['users'] = [] + 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, + })) + } + return this.follows.map(follow => ({ + handle: follow.handle, + displayName: follow.displayName, + })) + } + + // 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) + } + }) + } +} |