diff options
Diffstat (limited to 'src/state/models/content/list-membership.ts')
-rw-r--r-- | src/state/models/content/list-membership.ts | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/src/state/models/content/list-membership.ts b/src/state/models/content/list-membership.ts new file mode 100644 index 000000000..b4af4472b --- /dev/null +++ b/src/state/models/content/list-membership.ts @@ -0,0 +1,112 @@ +import {makeAutoObservable} from 'mobx' +import {AtUri, AppBskyGraphListitem} from '@atproto/api' +import {runInAction} from 'mobx' +import {RootStoreModel} from '../root-store' + +const PAGE_SIZE = 100 +interface Membership { + uri: string + value: AppBskyGraphListitem.Record +} + +export class ListMembershipModel { + // data + memberships: Membership[] = [] + + constructor(public rootStore: RootStoreModel, public subject: string) { + makeAutoObservable( + this, + { + rootStore: false, + }, + {autoBind: true}, + ) + } + + // public api + // = + + async fetch() { + // NOTE + // this approach to determining list membership is too inefficient to work at any scale + // it needs to be replaced with server side list membership queries + // -prf + let cursor + let records = [] + for (let i = 0; i < 100; i++) { + const res = await this.rootStore.agent.app.bsky.graph.listitem.list({ + repo: this.rootStore.me.did, + cursor, + limit: PAGE_SIZE, + }) + records = records.concat( + res.records.filter(record => record.value.subject === this.subject), + ) + cursor = res.cursor + if (!cursor) { + break + } + } + runInAction(() => { + this.memberships = records + }) + } + + getMembership(listUri: string) { + return this.memberships.find(m => m.value.list === listUri) + } + + isMember(listUri: string) { + return !!this.getMembership(listUri) + } + + async add(listUri: string) { + if (this.isMember(listUri)) { + return + } + const res = await this.rootStore.agent.app.bsky.graph.listitem.create( + { + repo: this.rootStore.me.did, + }, + { + subject: this.subject, + list: listUri, + createdAt: new Date().toISOString(), + }, + ) + const {rkey} = new AtUri(res.uri) + const record = await this.rootStore.agent.app.bsky.graph.listitem.get({ + repo: this.rootStore.me.did, + rkey, + }) + runInAction(() => { + this.memberships = this.memberships.concat([record]) + }) + } + + async remove(listUri: string) { + const membership = this.getMembership(listUri) + if (!membership) { + return + } + const {rkey} = new AtUri(membership.uri) + await this.rootStore.agent.app.bsky.graph.listitem.delete({ + repo: this.rootStore.me.did, + rkey, + }) + runInAction(() => { + this.memberships = this.memberships.filter(m => m.value.list !== listUri) + }) + } + + async updateTo(uris: string) { + for (const uri of uris) { + await this.add(uri) + } + for (const membership of this.memberships) { + if (!uris.includes(membership.value.list)) { + await this.remove(membership.value.list) + } + } + } +} |