Implement follow/unfollow
parent
adc25ce468
commit
1504d144d9
|
@ -97,6 +97,33 @@ export async function unrepost(adx: AdxClient, user: string, uri: string) {
|
|||
return numDels > 0
|
||||
}
|
||||
|
||||
export async function follow(
|
||||
adx: AdxClient,
|
||||
user: string,
|
||||
subject: {did: string; name: string},
|
||||
) {
|
||||
return await adx
|
||||
.repo(user, true)
|
||||
.collection('blueskyweb.xyz:Follows')
|
||||
.create('Follow', {
|
||||
$type: 'blueskyweb.xyz:Follow',
|
||||
subject,
|
||||
createdAt: new Date().toISOString(),
|
||||
})
|
||||
}
|
||||
|
||||
export async function unfollow(
|
||||
adx: AdxClient,
|
||||
user: string,
|
||||
subject: {did: string},
|
||||
) {
|
||||
const coll = adx.repo(user, true).collection('blueskyweb.xyz:Follows')
|
||||
const numDels = await deleteWhere(coll, 'Follow', record => {
|
||||
return record.value.subject.did === subject.did
|
||||
})
|
||||
return numDels > 0
|
||||
}
|
||||
|
||||
type WherePred = (_record: GetRecordResponseValidated) => Boolean
|
||||
async function deleteWhere(
|
||||
coll: AdxRepoCollectionClient,
|
||||
|
@ -104,7 +131,7 @@ async function deleteWhere(
|
|||
cond: WherePred,
|
||||
) {
|
||||
const toDelete: string[] = []
|
||||
iterateAll(coll, schema, record => {
|
||||
await iterateAll(coll, schema, record => {
|
||||
if (cond(record)) {
|
||||
toDelete.push(record.key)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {makeAutoObservable} from 'mobx'
|
||||
import {makeAutoObservable, runInAction} from 'mobx'
|
||||
import {bsky} from '@adxp/mock-api'
|
||||
import {RootStoreModel} from './root-store'
|
||||
import * as apilib from '../lib/api'
|
||||
|
||||
export class ProfileViewMyStateModel {
|
||||
hasFollowed: boolean = false
|
||||
|
@ -67,6 +68,27 @@ export class ProfileViewModel implements bsky.ProfileView.Response {
|
|||
await this._load()
|
||||
}
|
||||
|
||||
async toggleFollowing() {
|
||||
if (this.myState.hasFollowed) {
|
||||
await apilib.unfollow(this.rootStore.api, 'alice.com', {
|
||||
did: this.did,
|
||||
})
|
||||
runInAction(() => {
|
||||
this.followersCount--
|
||||
this.myState.hasFollowed = false
|
||||
})
|
||||
} else {
|
||||
await apilib.follow(this.rootStore.api, 'alice.com', {
|
||||
did: this.did,
|
||||
name: this.name,
|
||||
})
|
||||
runInAction(() => {
|
||||
this.followersCount++
|
||||
this.myState.hasFollowed = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// state transitions
|
||||
// =
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React, {useState, forwardRef, useImperativeHandle} from 'react'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {KeyboardAvoidingView, StyleSheet, TextInput, View} from 'react-native'
|
||||
import Toast from '../util/Toast'
|
||||
import ProgressCircle from '../util/ProgressCircle'
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
import React, {useState, useEffect} from 'react'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {ActivityIndicator, Image, StyleSheet, Text, View} from 'react-native'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
Image,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import {OnNavigateContent} from '../../routes/types'
|
||||
import {ProfileViewModel} from '../../../state/models/profile-view'
|
||||
import {useStores} from '../../../state'
|
||||
import {pluralize} from '../../lib/strings'
|
||||
import {s} from '../../lib/styles'
|
||||
import {AVIS} from '../../lib/assets'
|
||||
import Toast from '../util/Toast'
|
||||
|
||||
export const ProfileHeader = observer(function ProfileHeader({
|
||||
user,
|
||||
|
@ -29,6 +37,23 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||
newView.setup().catch(err => console.error('Failed to fetch profile', err))
|
||||
}, [user, view?.params.user, store])
|
||||
|
||||
const onPressToggleFollow = () => {
|
||||
view?.toggleFollowing().then(
|
||||
() => {
|
||||
Toast.show(
|
||||
`${view.myState.hasFollowed ? 'Following' : 'No longer following'} ${
|
||||
view.displayName || view.name
|
||||
}`,
|
||||
{
|
||||
duration: Toast.durations.LONG,
|
||||
position: Toast.positions.TOP,
|
||||
},
|
||||
)
|
||||
},
|
||||
err => console.error('Failed to toggle follow', err),
|
||||
)
|
||||
}
|
||||
|
||||
// loading
|
||||
// =
|
||||
if (
|
||||
|
@ -81,6 +106,12 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||
<Text style={s.gray}>{pluralize(view.postsCount, 'post')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View>
|
||||
<Button
|
||||
title={view.myState.hasFollowed ? 'Unfollow' : 'Follow'}
|
||||
onPress={onPressToggleFollow}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue