Add WIP post-thread view
This commit is contained in:
parent
19c694bc60
commit
c712cbbfe2
14 changed files with 534 additions and 25 deletions
|
@ -1,9 +1,9 @@
|
|||
import {makeAutoObservable, runInAction} from 'mobx'
|
||||
import {makeAutoObservable} from 'mobx'
|
||||
import {bsky} from '@adxp/mock-api'
|
||||
import {RootStoreModel} from './root-store'
|
||||
|
||||
export class FeedViewItemModel implements bsky.FeedView.FeedItem {
|
||||
key: string = ''
|
||||
_reactKey: string = ''
|
||||
uri: string = ''
|
||||
author: bsky.FeedView.User = {did: '', name: '', displayName: ''}
|
||||
repostedBy?: bsky.FeedView.User
|
||||
|
@ -17,9 +17,9 @@ export class FeedViewItemModel implements bsky.FeedView.FeedItem {
|
|||
likeCount: number = 0
|
||||
indexedAt: string = ''
|
||||
|
||||
constructor(key: string, v: bsky.FeedView.FeedItem) {
|
||||
constructor(reactKey: string, v: bsky.FeedView.FeedItem) {
|
||||
makeAutoObservable(this)
|
||||
this.key = key
|
||||
this._reactKey = reactKey
|
||||
Object.assign(this, v)
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,6 @@ export class FeedViewModel implements bsky.FeedView.Response {
|
|||
// =
|
||||
|
||||
private async _initialLoad() {
|
||||
console.log('_initialLoad()')
|
||||
this._xLoading()
|
||||
await new Promise(r => setTimeout(r, 1e3)) // DEBUG
|
||||
try {
|
||||
|
@ -131,7 +130,6 @@ export class FeedViewModel implements bsky.FeedView.Response {
|
|||
}
|
||||
|
||||
private async _loadMore() {
|
||||
console.log('_loadMore()')
|
||||
this._xLoading()
|
||||
await new Promise(r => setTimeout(r, 1e3)) // DEBUG
|
||||
try {
|
||||
|
@ -150,7 +148,6 @@ export class FeedViewModel implements bsky.FeedView.Response {
|
|||
}
|
||||
|
||||
private async _refresh() {
|
||||
console.log('_refresh()')
|
||||
this._xLoading(true)
|
||||
// TODO: refetch and update items
|
||||
await new Promise(r => setTimeout(r, 1e3)) // DEBUG
|
||||
|
|
153
src/state/models/post-thread-view.ts
Normal file
153
src/state/models/post-thread-view.ts
Normal file
|
@ -0,0 +1,153 @@
|
|||
import {makeAutoObservable, runInAction} from 'mobx'
|
||||
import {bsky, AdxUri} from '@adxp/mock-api'
|
||||
import _omit from 'lodash.omit'
|
||||
import {RootStoreModel} from './root-store'
|
||||
|
||||
export class PostThreadViewPostModel implements bsky.PostThreadView.Post {
|
||||
_reactKey: string = ''
|
||||
uri: string = ''
|
||||
author: bsky.PostThreadView.User = {did: '', name: '', displayName: ''}
|
||||
record: Record<string, unknown> = {}
|
||||
embed?:
|
||||
| bsky.PostThreadView.RecordEmbed
|
||||
| bsky.PostThreadView.ExternalEmbed
|
||||
| bsky.PostThreadView.UnknownEmbed
|
||||
replyCount: number = 0
|
||||
replies?: PostThreadViewPostModel[]
|
||||
repostCount: number = 0
|
||||
likeCount: number = 0
|
||||
indexedAt: string = ''
|
||||
|
||||
constructor(reactKey: string, v?: bsky.PostThreadView.Post) {
|
||||
makeAutoObservable(this)
|
||||
this._reactKey = reactKey
|
||||
if (v) {
|
||||
Object.assign(this, _omit(v, 'replies')) // copy everything but the replies
|
||||
}
|
||||
}
|
||||
|
||||
setReplies(v: bsky.PostThreadView.Post) {
|
||||
if (v.replies) {
|
||||
const replies = []
|
||||
let counter = 0
|
||||
for (const item of v.replies) {
|
||||
// TODO: validate .record
|
||||
const itemModel = new PostThreadViewPostModel(`item-${counter++}`, item)
|
||||
if (item.replies) {
|
||||
itemModel.setReplies(item)
|
||||
}
|
||||
replies.push(itemModel)
|
||||
}
|
||||
this.replies = replies
|
||||
}
|
||||
}
|
||||
}
|
||||
const UNLOADED_THREAD = new PostThreadViewPostModel('')
|
||||
|
||||
export class PostThreadViewModel implements bsky.PostThreadView.Response {
|
||||
isLoading = false
|
||||
isRefreshing = false
|
||||
hasLoaded = false
|
||||
error = ''
|
||||
resolvedUri = ''
|
||||
params: bsky.PostThreadView.Params
|
||||
thread: PostThreadViewPostModel = UNLOADED_THREAD
|
||||
|
||||
constructor(
|
||||
public rootStore: RootStoreModel,
|
||||
params: bsky.PostThreadView.Params,
|
||||
) {
|
||||
makeAutoObservable(
|
||||
this,
|
||||
{
|
||||
rootStore: false,
|
||||
params: false,
|
||||
},
|
||||
{autoBind: true},
|
||||
)
|
||||
this.params = params
|
||||
}
|
||||
|
||||
get hasContent() {
|
||||
return this.thread !== UNLOADED_THREAD
|
||||
}
|
||||
|
||||
get hasError() {
|
||||
return this.error !== ''
|
||||
}
|
||||
|
||||
// public api
|
||||
// =
|
||||
|
||||
async setup() {
|
||||
if (!this.resolvedUri) {
|
||||
await this._resolveUri()
|
||||
}
|
||||
if (this.hasContent) {
|
||||
await this._refresh()
|
||||
} else {
|
||||
await this._initialLoad()
|
||||
}
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
await this._refresh()
|
||||
}
|
||||
|
||||
// state transitions
|
||||
// =
|
||||
|
||||
private _xLoading(isRefreshing = false) {
|
||||
this.isLoading = true
|
||||
this.isRefreshing = isRefreshing
|
||||
this.error = ''
|
||||
}
|
||||
|
||||
private _xIdle(err: string = '') {
|
||||
this.isLoading = false
|
||||
this.isRefreshing = false
|
||||
this.hasLoaded = true
|
||||
this.error = err
|
||||
}
|
||||
|
||||
// loader functions
|
||||
// =
|
||||
|
||||
private async _resolveUri() {
|
||||
const urip = new AdxUri(this.params.uri)
|
||||
if (!urip.host.startsWith('did:')) {
|
||||
urip.host = await this.rootStore.resolveName(urip.host)
|
||||
}
|
||||
runInAction(() => {
|
||||
this.resolvedUri = urip.toString()
|
||||
})
|
||||
}
|
||||
|
||||
private async _initialLoad() {
|
||||
this._xLoading()
|
||||
try {
|
||||
const res = (await this.rootStore.api.mainPds.view(
|
||||
'blueskyweb.xyz:PostThreadView',
|
||||
Object.assign({}, this.params, {uri: this.resolvedUri}),
|
||||
)) as bsky.PostThreadView.Response
|
||||
this._replaceAll(res)
|
||||
this._xIdle()
|
||||
} catch (e: any) {
|
||||
this._xIdle(`Failed to load thread: ${e.toString()}`)
|
||||
}
|
||||
}
|
||||
|
||||
private async _refresh() {
|
||||
this._xLoading(true)
|
||||
// TODO: refetch and update items
|
||||
await new Promise(r => setTimeout(r, 1e3)) // DEBUG
|
||||
this._xIdle()
|
||||
}
|
||||
|
||||
private _replaceAll(res: bsky.PostThreadView.Response) {
|
||||
// TODO: validate .record
|
||||
const thread = new PostThreadViewPostModel('item-0', res.thread)
|
||||
thread.setReplies(res.thread)
|
||||
this.thread = thread
|
||||
}
|
||||
}
|
|
@ -18,11 +18,18 @@ export class RootStoreModel {
|
|||
constructor(public api: AdxClient) {
|
||||
makeAutoObservable(this, {
|
||||
api: false,
|
||||
resolveName: false,
|
||||
serialize: false,
|
||||
hydrate: false,
|
||||
})
|
||||
}
|
||||
|
||||
async resolveName(didOrName: string) {
|
||||
const userDb = this.api.mockDb.getUser(didOrName)
|
||||
if (!userDb) throw new Error(`User not found: ${didOrName}`)
|
||||
return userDb.did
|
||||
}
|
||||
|
||||
serialize(): unknown {
|
||||
return {
|
||||
session: this.session.serialize(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue