Remove scenes (#36)
* Remove scenes from the main menu * Remove scenes from the profile view * Remove 'scenes explainer' from onboarding flow * Remove scene-related modals * Remove member/membership code * Remove all scenes-related items from notifications * Remove scene-related code from posts feed * Remove scene-related API helpers * Update tests
This commit is contained in:
parent
5abcc8e336
commit
bf1092ad86
29 changed files with 18 additions and 1714 deletions
|
@ -216,54 +216,6 @@ export async function unfollow(store: RootStoreModel, followUri: string) {
|
|||
})
|
||||
}
|
||||
|
||||
export async function inviteToScene(
|
||||
store: RootStoreModel,
|
||||
sceneDid: string,
|
||||
subjectDid: string,
|
||||
subjectDeclarationCid: string,
|
||||
): Promise<string> {
|
||||
const res = await store.api.app.bsky.graph.assertion.create(
|
||||
{
|
||||
did: sceneDid,
|
||||
},
|
||||
{
|
||||
subject: {
|
||||
did: subjectDid,
|
||||
declarationCid: subjectDeclarationCid,
|
||||
},
|
||||
assertion: APP_BSKY_GRAPH.AssertMember,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
)
|
||||
return res.uri
|
||||
}
|
||||
|
||||
interface Confirmation {
|
||||
originator: {
|
||||
did: string
|
||||
declarationCid: string
|
||||
}
|
||||
assertion: {
|
||||
uri: string
|
||||
cid: string
|
||||
}
|
||||
}
|
||||
export async function acceptSceneInvite(
|
||||
store: RootStoreModel,
|
||||
details: Confirmation,
|
||||
): Promise<string> {
|
||||
const res = await store.api.app.bsky.graph.confirmation.create(
|
||||
{
|
||||
did: store.me.did || '',
|
||||
},
|
||||
{
|
||||
...details,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
)
|
||||
return res.uri
|
||||
}
|
||||
|
||||
interface FetchHandlerResponse {
|
||||
status: number
|
||||
headers: Record<string, string>
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
AppBskyFeedGetAuthorFeed as GetAuthorFeed,
|
||||
} from '@atproto/api'
|
||||
type FeedViewPost = AppBskyFeedFeedViewPost.Main
|
||||
type ReasonTrend = AppBskyFeedFeedViewPost.ReasonTrend
|
||||
type ReasonRepost = AppBskyFeedFeedViewPost.ReasonRepost
|
||||
type PostView = AppBskyFeedPost.View
|
||||
import {AtUri} from '../../third-party/uri'
|
||||
|
@ -94,12 +93,6 @@ export class FeedItemModel {
|
|||
}
|
||||
}
|
||||
|
||||
get reasonTrend(): ReasonTrend | undefined {
|
||||
if (this.reason?.$type === 'app.bsky.feed.feedViewPost#reasonTrend') {
|
||||
return this.reason as ReasonTrend
|
||||
}
|
||||
}
|
||||
|
||||
async toggleUpvote() {
|
||||
const wasUpvoted = !!this.post.viewer.upvote
|
||||
const wasDownvoted = !!this.post.viewer.downvote
|
||||
|
@ -494,10 +487,9 @@ export class FeedModel {
|
|||
private _updateAll(res: GetTimeline.Response | GetAuthorFeed.Response) {
|
||||
for (const item of res.data.feed) {
|
||||
const existingItem = this.feed.find(
|
||||
// HACK: need to find the reposts and trends item, so we have to check for that -prf
|
||||
// HACK: need to find the reposts' item, so we have to check for that -prf
|
||||
item2 =>
|
||||
item.post.uri === item2.post.uri &&
|
||||
item.reason?.$trend === item2.reason?.$trend &&
|
||||
// @ts-ignore todo
|
||||
item.reason?.by?.did === item2.reason?.by?.did,
|
||||
)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {makeAutoObservable, runInAction} from 'mobx'
|
||||
import {RootStoreModel} from './root-store'
|
||||
import {FeedModel} from './feed-view'
|
||||
import {MembershipsViewModel} from './memberships-view'
|
||||
import {NotificationsViewModel} from './notifications-view'
|
||||
import {isObj, hasProp} from '../lib/type-guards'
|
||||
|
||||
|
@ -12,7 +11,6 @@ export class MeModel {
|
|||
description: string = ''
|
||||
avatar: string = ''
|
||||
notificationCount: number = 0
|
||||
memberships?: MembershipsViewModel
|
||||
mainFeed: FeedModel
|
||||
notifications: NotificationsViewModel
|
||||
|
||||
|
@ -35,7 +33,6 @@ export class MeModel {
|
|||
this.description = ''
|
||||
this.avatar = ''
|
||||
this.notificationCount = 0
|
||||
this.memberships = undefined
|
||||
}
|
||||
|
||||
serialize(): unknown {
|
||||
|
@ -99,13 +96,7 @@ export class MeModel {
|
|||
algorithm: 'reverse-chronological',
|
||||
})
|
||||
this.notifications = new NotificationsViewModel(this.rootStore, {})
|
||||
this.memberships = new MembershipsViewModel(this.rootStore, {
|
||||
actor: this.did,
|
||||
})
|
||||
await Promise.all([
|
||||
this.memberships?.setup().catch(e => {
|
||||
this.rootStore.log.error('Failed to setup memberships model', e)
|
||||
}),
|
||||
this.mainFeed.setup().catch(e => {
|
||||
this.rootStore.log.error('Failed to setup main feed model', e)
|
||||
}),
|
||||
|
@ -133,8 +124,4 @@ export class MeModel {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
async refreshMemberships() {
|
||||
return this.memberships?.refresh()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
import {makeAutoObservable, runInAction} from 'mobx'
|
||||
import {
|
||||
AppBskyGraphGetMembers as GetMembers,
|
||||
AppBskyActorRef as ActorRef,
|
||||
APP_BSKY_GRAPH,
|
||||
} from '@atproto/api'
|
||||
import {AtUri} from '../../third-party/uri'
|
||||
import {RootStoreModel} from './root-store'
|
||||
|
||||
export type MemberItem = GetMembers.Member & {
|
||||
_reactKey: string
|
||||
}
|
||||
|
||||
export class MembersViewModel {
|
||||
// state
|
||||
isLoading = false
|
||||
isRefreshing = false
|
||||
hasLoaded = false
|
||||
error = ''
|
||||
params: GetMembers.QueryParams
|
||||
|
||||
// data
|
||||
subject: ActorRef.WithInfo = {
|
||||
did: '',
|
||||
handle: '',
|
||||
displayName: '',
|
||||
declaration: {cid: '', actorType: ''},
|
||||
avatar: undefined,
|
||||
}
|
||||
members: MemberItem[] = []
|
||||
|
||||
constructor(
|
||||
public rootStore: RootStoreModel,
|
||||
params: GetMembers.QueryParams,
|
||||
) {
|
||||
makeAutoObservable(
|
||||
this,
|
||||
{
|
||||
rootStore: false,
|
||||
params: false,
|
||||
},
|
||||
{autoBind: true},
|
||||
)
|
||||
this.params = params
|
||||
}
|
||||
|
||||
get hasContent() {
|
||||
return this.members.length !== 0
|
||||
}
|
||||
|
||||
get hasError() {
|
||||
return this.error !== ''
|
||||
}
|
||||
|
||||
get isEmpty() {
|
||||
return this.hasLoaded && !this.hasContent
|
||||
}
|
||||
|
||||
isMember(did: string) {
|
||||
return this.members.find(member => member.did === did)
|
||||
}
|
||||
|
||||
// public api
|
||||
// =
|
||||
|
||||
async setup() {
|
||||
await this._fetch()
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
await this._fetch(true)
|
||||
}
|
||||
|
||||
async loadMore() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
async removeMember(did: string) {
|
||||
const assertsRes = await this.rootStore.api.app.bsky.graph.getAssertions({
|
||||
author: this.subject.did,
|
||||
subject: did,
|
||||
assertion: APP_BSKY_GRAPH.AssertMember,
|
||||
})
|
||||
if (assertsRes.data.assertions.length < 1) {
|
||||
throw new Error('Could not find membership record')
|
||||
}
|
||||
for (const assert of assertsRes.data.assertions) {
|
||||
await this.rootStore.api.app.bsky.graph.assertion.delete({
|
||||
did: this.subject.did,
|
||||
rkey: new AtUri(assert.uri).rkey,
|
||||
})
|
||||
}
|
||||
runInAction(() => {
|
||||
this.members = this.members.filter(m => m.did !== did)
|
||||
})
|
||||
}
|
||||
|
||||
// state transitions
|
||||
// =
|
||||
|
||||
private _xLoading(isRefreshing = false) {
|
||||
this.isLoading = true
|
||||
this.isRefreshing = isRefreshing
|
||||
this.error = ''
|
||||
}
|
||||
|
||||
private _xIdle(err?: any) {
|
||||
this.isLoading = false
|
||||
this.isRefreshing = false
|
||||
this.hasLoaded = true
|
||||
this.error = err ? err.toString() : ''
|
||||
if (err) {
|
||||
this.rootStore.log.error('Failed to fetch members', err)
|
||||
}
|
||||
}
|
||||
|
||||
// loader functions
|
||||
// =
|
||||
|
||||
private async _fetch(isRefreshing = false) {
|
||||
this._xLoading(isRefreshing)
|
||||
try {
|
||||
const res = await this.rootStore.api.app.bsky.graph.getMembers(
|
||||
this.params,
|
||||
)
|
||||
this._replaceAll(res)
|
||||
this._xIdle()
|
||||
} catch (e: any) {
|
||||
this._xIdle(e)
|
||||
}
|
||||
}
|
||||
|
||||
private _replaceAll(res: GetMembers.Response) {
|
||||
this.subject.did = res.data.subject.did
|
||||
this.subject.handle = res.data.subject.handle
|
||||
this.subject.displayName = res.data.subject.displayName
|
||||
this.subject.declaration = res.data.subject.declaration
|
||||
this.subject.avatar = res.data.subject.avatar
|
||||
this.members.length = 0
|
||||
let counter = 0
|
||||
for (const item of res.data.members) {
|
||||
this._append({_reactKey: `item-${counter++}`, ...item})
|
||||
}
|
||||
}
|
||||
|
||||
private _append(item: MemberItem) {
|
||||
this.members.push(item)
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
import {makeAutoObservable} from 'mobx'
|
||||
import {
|
||||
AppBskyGraphGetMemberships as GetMemberships,
|
||||
AppBskyActorRef as ActorRef,
|
||||
} from '@atproto/api'
|
||||
import {RootStoreModel} from './root-store'
|
||||
|
||||
export type MembershipItem = GetMemberships.Membership & {
|
||||
_reactKey: string
|
||||
}
|
||||
|
||||
export class MembershipsViewModel {
|
||||
// state
|
||||
isLoading = false
|
||||
isRefreshing = false
|
||||
hasLoaded = false
|
||||
error = ''
|
||||
params: GetMemberships.QueryParams
|
||||
|
||||
// data
|
||||
subject: ActorRef.WithInfo = {
|
||||
did: '',
|
||||
handle: '',
|
||||
displayName: '',
|
||||
declaration: {cid: '', actorType: ''},
|
||||
avatar: undefined,
|
||||
}
|
||||
memberships: MembershipItem[] = []
|
||||
|
||||
constructor(
|
||||
public rootStore: RootStoreModel,
|
||||
params: GetMemberships.QueryParams,
|
||||
) {
|
||||
makeAutoObservable(
|
||||
this,
|
||||
{
|
||||
rootStore: false,
|
||||
params: false,
|
||||
},
|
||||
{autoBind: true},
|
||||
)
|
||||
this.params = params
|
||||
}
|
||||
|
||||
get hasContent() {
|
||||
return this.memberships.length !== 0
|
||||
}
|
||||
|
||||
get hasError() {
|
||||
return this.error !== ''
|
||||
}
|
||||
|
||||
get isEmpty() {
|
||||
return this.hasLoaded && !this.hasContent
|
||||
}
|
||||
|
||||
isMemberOf(did: string) {
|
||||
return !!this.memberships.find(m => m.did === did)
|
||||
}
|
||||
|
||||
// public api
|
||||
// =
|
||||
|
||||
async setup() {
|
||||
await this._fetch()
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
await this._fetch(true)
|
||||
}
|
||||
|
||||
async loadMore() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// state transitions
|
||||
// =
|
||||
|
||||
private _xLoading(isRefreshing = false) {
|
||||
this.isLoading = true
|
||||
this.isRefreshing = isRefreshing
|
||||
this.error = ''
|
||||
}
|
||||
|
||||
private _xIdle(err?: any) {
|
||||
this.isLoading = false
|
||||
this.isRefreshing = false
|
||||
this.hasLoaded = true
|
||||
this.error = err ? err.toString() : ''
|
||||
if (err) {
|
||||
this.rootStore.log.error('Failed to fetch memberships', err)
|
||||
}
|
||||
}
|
||||
|
||||
// loader functions
|
||||
// =
|
||||
|
||||
private async _fetch(isRefreshing = false) {
|
||||
this._xLoading(isRefreshing)
|
||||
try {
|
||||
const res = await this.rootStore.api.app.bsky.graph.getMemberships(
|
||||
this.params,
|
||||
)
|
||||
this._replaceAll(res)
|
||||
this._xIdle()
|
||||
} catch (e: any) {
|
||||
this._xIdle(e)
|
||||
}
|
||||
}
|
||||
|
||||
private _replaceAll(res: GetMemberships.Response) {
|
||||
this.subject.did = res.data.subject.did
|
||||
this.subject.handle = res.data.subject.handle
|
||||
this.subject.displayName = res.data.subject.displayName
|
||||
this.subject.declaration = res.data.subject.declaration
|
||||
this.subject.avatar = res.data.subject.avatar
|
||||
this.memberships.length = 0
|
||||
let counter = 0
|
||||
for (const item of res.data.memberships) {
|
||||
this._append({_reactKey: `item-${counter++}`, ...item})
|
||||
}
|
||||
}
|
||||
|
||||
private _append(item: MembershipItem) {
|
||||
this.memberships.push(item)
|
||||
}
|
||||
}
|
|
@ -4,17 +4,15 @@ import {
|
|||
AppBskyActorRef as ActorRef,
|
||||
AppBskyFeedPost,
|
||||
AppBskyFeedRepost,
|
||||
AppBskyFeedTrend,
|
||||
AppBskyFeedVote,
|
||||
AppBskyGraphAssertion,
|
||||
AppBskyGraphFollow,
|
||||
APP_BSKY_GRAPH,
|
||||
} from '@atproto/api'
|
||||
import {RootStoreModel} from './root-store'
|
||||
import {PostThreadViewModel} from './post-thread-view'
|
||||
import {cleanError} from '../../lib/strings'
|
||||
|
||||
const UNGROUPABLE_REASONS = ['trend', 'assertion']
|
||||
const UNGROUPABLE_REASONS = ['assertion']
|
||||
const PAGE_SIZE = 30
|
||||
const MS_60MIN = 1e3 * 60 * 60
|
||||
|
||||
|
@ -27,7 +25,6 @@ export interface GroupedNotification extends ListNotifications.Notification {
|
|||
type SupportedRecord =
|
||||
| AppBskyFeedPost.Record
|
||||
| AppBskyFeedRepost.Record
|
||||
| AppBskyFeedTrend.Record
|
||||
| AppBskyFeedVote.Record
|
||||
| AppBskyGraphAssertion.Record
|
||||
| AppBskyGraphFollow.Record
|
||||
|
@ -94,10 +91,6 @@ export class NotificationsViewItemModel {
|
|||
return this.reason === 'repost'
|
||||
}
|
||||
|
||||
get isTrend() {
|
||||
return this.reason === 'trend'
|
||||
}
|
||||
|
||||
get isMention() {
|
||||
return this.reason === 'mention'
|
||||
}
|
||||
|
@ -115,26 +108,12 @@ export class NotificationsViewItemModel {
|
|||
}
|
||||
|
||||
get needsAdditionalData() {
|
||||
if (
|
||||
this.isUpvote ||
|
||||
this.isRepost ||
|
||||
this.isTrend ||
|
||||
this.isReply ||
|
||||
this.isMention
|
||||
) {
|
||||
if (this.isUpvote || this.isRepost || this.isReply || this.isMention) {
|
||||
return !this.additionalPost
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
get isInvite() {
|
||||
return (
|
||||
this.isAssertion &&
|
||||
AppBskyGraphAssertion.isRecord(this.record) &&
|
||||
this.record.assertion === APP_BSKY_GRAPH.AssertMember
|
||||
)
|
||||
}
|
||||
|
||||
get subjectUri(): string {
|
||||
if (this.reasonSubject) {
|
||||
return this.reasonSubject
|
||||
|
@ -142,7 +121,6 @@ export class NotificationsViewItemModel {
|
|||
const record = this.record
|
||||
if (
|
||||
AppBskyFeedRepost.isRecord(record) ||
|
||||
AppBskyFeedTrend.isRecord(record) ||
|
||||
AppBskyFeedVote.isRecord(record)
|
||||
) {
|
||||
return record.subject.uri
|
||||
|
@ -154,7 +132,6 @@ export class NotificationsViewItemModel {
|
|||
for (const ns of [
|
||||
AppBskyFeedPost,
|
||||
AppBskyFeedRepost,
|
||||
AppBskyFeedTrend,
|
||||
AppBskyFeedVote,
|
||||
AppBskyGraphAssertion,
|
||||
AppBskyGraphFollow,
|
||||
|
@ -185,7 +162,7 @@ export class NotificationsViewItemModel {
|
|||
let postUri
|
||||
if (this.isReply || this.isMention) {
|
||||
postUri = this.uri
|
||||
} else if (this.isUpvote || this.isRepost || this.isTrend) {
|
||||
} else if (this.isUpvote || this.isRepost) {
|
||||
postUri = this.subjectUri
|
||||
}
|
||||
if (postUri) {
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
import {makeAutoObservable} from 'mobx'
|
||||
import {RootStoreModel} from './root-store'
|
||||
import {ProfileViewModel} from './profile-view'
|
||||
import {MembersViewModel} from './members-view'
|
||||
import {MembershipsViewModel} from './memberships-view'
|
||||
import {FeedModel} from './feed-view'
|
||||
|
||||
export enum Sections {
|
||||
Posts = 'Posts',
|
||||
PostsWithReplies = 'Posts & replies',
|
||||
Scenes = 'Scenes',
|
||||
Trending = 'Trending',
|
||||
Members = 'Members',
|
||||
}
|
||||
|
||||
const USER_SELECTOR_ITEMS = [
|
||||
Sections.Posts,
|
||||
Sections.PostsWithReplies,
|
||||
Sections.Scenes,
|
||||
]
|
||||
const SCENE_SELECTOR_ITEMS = [Sections.Trending, Sections.Members]
|
||||
const USER_SELECTOR_ITEMS = [Sections.Posts, Sections.PostsWithReplies]
|
||||
|
||||
export interface ProfileUiParams {
|
||||
user: string
|
||||
|
@ -28,8 +18,6 @@ export class ProfileUiModel {
|
|||
// data
|
||||
profile: ProfileViewModel
|
||||
feed: FeedModel
|
||||
memberships: MembershipsViewModel
|
||||
members: MembersViewModel
|
||||
|
||||
// ui state
|
||||
selectedViewIndex = 0
|
||||
|
@ -51,24 +39,15 @@ export class ProfileUiModel {
|
|||
author: params.user,
|
||||
limit: 10,
|
||||
})
|
||||
this.memberships = new MembershipsViewModel(rootStore, {actor: params.user})
|
||||
this.members = new MembersViewModel(rootStore, {actor: params.user})
|
||||
}
|
||||
|
||||
get currentView(): FeedModel | MembershipsViewModel | MembersViewModel {
|
||||
get currentView(): FeedModel {
|
||||
if (
|
||||
this.selectedView === Sections.Posts ||
|
||||
this.selectedView === Sections.PostsWithReplies ||
|
||||
this.selectedView === Sections.Trending
|
||||
this.selectedView === Sections.PostsWithReplies
|
||||
) {
|
||||
return this.feed
|
||||
}
|
||||
if (this.selectedView === Sections.Scenes) {
|
||||
return this.memberships
|
||||
}
|
||||
if (this.selectedView === Sections.Members) {
|
||||
return this.members
|
||||
}
|
||||
throw new Error(`Invalid selector value: ${this.selectedViewIndex}`)
|
||||
}
|
||||
|
||||
|
@ -85,15 +64,9 @@ export class ProfileUiModel {
|
|||
return this.profile.isUser
|
||||
}
|
||||
|
||||
get isScene() {
|
||||
return this.profile.isScene
|
||||
}
|
||||
|
||||
get selectorItems() {
|
||||
if (this.isUser) {
|
||||
return USER_SELECTOR_ITEMS
|
||||
} else if (this.isScene) {
|
||||
return SCENE_SELECTOR_ITEMS
|
||||
} else {
|
||||
return USER_SELECTOR_ITEMS
|
||||
}
|
||||
|
@ -119,16 +92,6 @@ export class ProfileUiModel {
|
|||
.setup()
|
||||
.catch(err => this.rootStore.log.error('Failed to fetch feed', err)),
|
||||
])
|
||||
if (this.isUser) {
|
||||
await this.memberships
|
||||
.setup()
|
||||
.catch(err => this.rootStore.log.error('Failed to fetch members', err))
|
||||
}
|
||||
if (this.isScene) {
|
||||
await this.members
|
||||
.setup()
|
||||
.catch(err => this.rootStore.log.error('Failed to fetch members', err))
|
||||
}
|
||||
}
|
||||
|
||||
async update() {
|
||||
|
|
|
@ -13,11 +13,9 @@ import {RootStoreModel} from './root-store'
|
|||
import * as apilib from '../lib/api'
|
||||
|
||||
export const ACTOR_TYPE_USER = 'app.bsky.system.actorUser'
|
||||
export const ACTOR_TYPE_SCENE = 'app.bsky.system.actorScene'
|
||||
|
||||
export class ProfileViewMyStateModel {
|
||||
follow?: string
|
||||
member?: string
|
||||
muted?: boolean
|
||||
|
||||
constructor() {
|
||||
|
@ -47,7 +45,6 @@ export class ProfileViewModel {
|
|||
banner?: string
|
||||
followersCount: number = 0
|
||||
followsCount: number = 0
|
||||
membersCount: number = 0
|
||||
postsCount: number = 0
|
||||
myState = new ProfileViewMyStateModel()
|
||||
|
||||
|
@ -85,10 +82,6 @@ export class ProfileViewModel {
|
|||
return this.declaration.actorType === ACTOR_TYPE_USER
|
||||
}
|
||||
|
||||
get isScene() {
|
||||
return this.declaration.actorType === ACTOR_TYPE_SCENE
|
||||
}
|
||||
|
||||
// public api
|
||||
// =
|
||||
|
||||
|
@ -216,7 +209,6 @@ export class ProfileViewModel {
|
|||
this.banner = res.data.banner
|
||||
this.followersCount = res.data.followersCount
|
||||
this.followsCount = res.data.followsCount
|
||||
this.membersCount = res.data.membersCount
|
||||
this.postsCount = res.data.postsCount
|
||||
if (res.data.myState) {
|
||||
Object.assign(this.myState, res.data.myState)
|
||||
|
|
|
@ -25,22 +25,6 @@ export class EditProfileModal {
|
|||
}
|
||||
}
|
||||
|
||||
export class CreateSceneModal {
|
||||
name = 'create-scene'
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this)
|
||||
}
|
||||
}
|
||||
|
||||
export class InviteToSceneModal {
|
||||
name = 'invite-to-scene'
|
||||
|
||||
constructor(public profileView: ProfileViewModel) {
|
||||
makeAutoObservable(this)
|
||||
}
|
||||
}
|
||||
|
||||
export class ServerInputModal {
|
||||
name = 'server-input'
|
||||
|
||||
|
@ -143,7 +127,6 @@ export class ShellUiModel {
|
|||
activeModal:
|
||||
| ConfirmModal
|
||||
| EditProfileModal
|
||||
| CreateSceneModal
|
||||
| ServerInputModal
|
||||
| ReportPostModal
|
||||
| ReportAccountModal
|
||||
|
@ -191,7 +174,6 @@ export class ShellUiModel {
|
|||
modal:
|
||||
| ConfirmModal
|
||||
| EditProfileModal
|
||||
| CreateSceneModal
|
||||
| ServerInputModal
|
||||
| ReportPostModal
|
||||
| ReportAccountModal,
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
import {makeAutoObservable, runInAction} from 'mobx'
|
||||
import {RootStoreModel} from './root-store'
|
||||
import {UserFollowsViewModel, FollowItem} from './user-follows-view'
|
||||
import {GetAssertionsView} from './get-assertions-view'
|
||||
import {APP_BSKY_SYSTEM, APP_BSKY_GRAPH} from '@atproto/api'
|
||||
|
||||
export interface SuggestedInvitesViewParams {
|
||||
sceneDid: string
|
||||
}
|
||||
|
||||
export class SuggestedInvitesView {
|
||||
// state
|
||||
isLoading = false
|
||||
isRefreshing = false
|
||||
hasLoaded = false
|
||||
error = ''
|
||||
params: SuggestedInvitesViewParams
|
||||
sceneAssertionsView: GetAssertionsView
|
||||
myFollowsView: UserFollowsViewModel
|
||||
|
||||
// data
|
||||
suggestions: FollowItem[] = []
|
||||
|
||||
constructor(
|
||||
public rootStore: RootStoreModel,
|
||||
params: SuggestedInvitesViewParams,
|
||||
) {
|
||||
makeAutoObservable(
|
||||
this,
|
||||
{
|
||||
rootStore: false,
|
||||
params: false,
|
||||
},
|
||||
{autoBind: true},
|
||||
)
|
||||
this.params = params
|
||||
this.sceneAssertionsView = new GetAssertionsView(rootStore, {
|
||||
author: params.sceneDid,
|
||||
assertion: APP_BSKY_GRAPH.AssertMember,
|
||||
})
|
||||
this.myFollowsView = new UserFollowsViewModel(rootStore, {
|
||||
user: rootStore.me.did || '',
|
||||
})
|
||||
}
|
||||
|
||||
get hasContent() {
|
||||
return this.suggestions.length > 0
|
||||
}
|
||||
|
||||
get hasError() {
|
||||
return this.error !== ''
|
||||
}
|
||||
|
||||
get isEmpty() {
|
||||
return this.hasLoaded && !this.hasContent
|
||||
}
|
||||
|
||||
get unconfirmed() {
|
||||
return this.sceneAssertionsView.unconfirmed
|
||||
}
|
||||
|
||||
// public api
|
||||
// =
|
||||
|
||||
async setup() {
|
||||
await this._fetch(false)
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
await this._fetch(true)
|
||||
}
|
||||
|
||||
async loadMore() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// state transitions
|
||||
// =
|
||||
|
||||
private _xLoading(isRefreshing = false) {
|
||||
this.isLoading = true
|
||||
this.isRefreshing = isRefreshing
|
||||
this.error = ''
|
||||
}
|
||||
|
||||
private _xIdle(err?: any) {
|
||||
this.isLoading = false
|
||||
this.isRefreshing = false
|
||||
this.hasLoaded = true
|
||||
this.error = err ? err.toString() : ''
|
||||
if (err) {
|
||||
this.rootStore.log.error('Failed to fetch suggested invites', err)
|
||||
}
|
||||
}
|
||||
|
||||
// loader functions
|
||||
// =
|
||||
|
||||
private async _fetch(isRefreshing = false) {
|
||||
this._xLoading(isRefreshing)
|
||||
try {
|
||||
// TODO need to fetch all!
|
||||
await this.sceneAssertionsView.setup()
|
||||
} catch (e: any) {
|
||||
this.rootStore.log.error(
|
||||
'Failed to fetch current scene members in suggested invites',
|
||||
e,
|
||||
)
|
||||
this._xIdle(
|
||||
'Failed to fetch the current scene members. Check your internet connection and try again.',
|
||||
)
|
||||
return
|
||||
}
|
||||
try {
|
||||
await this.myFollowsView.setup()
|
||||
} catch (e: any) {
|
||||
this.rootStore.log.error(
|
||||
'Failed to fetch current followers in suggested invites',
|
||||
e,
|
||||
)
|
||||
this._xIdle(
|
||||
'Failed to fetch the your current followers. Check your internet connection and try again.',
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// collect all followed users that arent already in the scene
|
||||
const newSuggestions: FollowItem[] = []
|
||||
for (const follow of this.myFollowsView.follows) {
|
||||
if (follow.declaration.actorType !== APP_BSKY_SYSTEM.ActorUser) {
|
||||
continue
|
||||
}
|
||||
if (!this.sceneAssertionsView.getBySubject(follow.did)) {
|
||||
newSuggestions.push(follow)
|
||||
}
|
||||
}
|
||||
runInAction(() => {
|
||||
this.suggestions = newSuggestions
|
||||
})
|
||||
this._xIdle()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue