diff --git a/__tests__/view/shell/mobile/Menu.test.tsx b/__tests__/view/shell/mobile/Menu.test.tsx index 5eee3f12..caec5f29 100644 --- a/__tests__/view/shell/mobile/Menu.test.tsx +++ b/__tests__/view/shell/mobile/Menu.test.tsx @@ -57,14 +57,4 @@ describe('Menu', () => { expect(onCloseMock).toHaveBeenCalled() expect(mockedNavigationStore.switchTo).toHaveBeenCalledWith(1, true) }) - - it('presses new scene button', () => { - const {getAllByTestId} = render() - - const menuItemButton = getAllByTestId('menuItemButton') - fireEvent.press(menuItemButton[3]) - - expect(onCloseMock).toHaveBeenCalled() - expect(mockedShellStore.openModal).toHaveBeenCalled() - }) }) diff --git a/public/img/scene-explainer.jpg b/public/img/scene-explainer.jpg deleted file mode 100644 index 2478b055..00000000 Binary files a/public/img/scene-explainer.jpg and /dev/null differ diff --git a/src/state/lib/api.ts b/src/state/lib/api.ts index e701ae6f..8dc9ce5f 100644 --- a/src/state/lib/api.ts +++ b/src/state/lib/api.ts @@ -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 { - 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 { - 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 diff --git a/src/state/models/feed-view.ts b/src/state/models/feed-view.ts index 5f2b9721..c39daf87 100644 --- a/src/state/models/feed-view.ts +++ b/src/state/models/feed-view.ts @@ -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, ) diff --git a/src/state/models/me.ts b/src/state/models/me.ts index 0ae52db8..201ce04c 100644 --- a/src/state/models/me.ts +++ b/src/state/models/me.ts @@ -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() - } } diff --git a/src/state/models/members-view.ts b/src/state/models/members-view.ts deleted file mode 100644 index 73295f47..00000000 --- a/src/state/models/members-view.ts +++ /dev/null @@ -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) - } -} diff --git a/src/state/models/memberships-view.ts b/src/state/models/memberships-view.ts deleted file mode 100644 index 661b3f6a..00000000 --- a/src/state/models/memberships-view.ts +++ /dev/null @@ -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) - } -} diff --git a/src/state/models/notifications-view.ts b/src/state/models/notifications-view.ts index c169a995..c4d2b2df 100644 --- a/src/state/models/notifications-view.ts +++ b/src/state/models/notifications-view.ts @@ -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) { diff --git a/src/state/models/profile-ui.ts b/src/state/models/profile-ui.ts index fb90fb69..55fb2506 100644 --- a/src/state/models/profile-ui.ts +++ b/src/state/models/profile-ui.ts @@ -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() { diff --git a/src/state/models/profile-view.ts b/src/state/models/profile-view.ts index 2670627c..a1535693 100644 --- a/src/state/models/profile-view.ts +++ b/src/state/models/profile-view.ts @@ -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) diff --git a/src/state/models/shell-ui.ts b/src/state/models/shell-ui.ts index 52d08168..1af74f56 100644 --- a/src/state/models/shell-ui.ts +++ b/src/state/models/shell-ui.ts @@ -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, diff --git a/src/state/models/suggested-invites-view.ts b/src/state/models/suggested-invites-view.ts deleted file mode 100644 index fadc956c..00000000 --- a/src/state/models/suggested-invites-view.ts +++ /dev/null @@ -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() - } -} diff --git a/src/view/com/modals/CreateScene.tsx b/src/view/com/modals/CreateScene.tsx deleted file mode 100644 index d92fe2e3..00000000 --- a/src/view/com/modals/CreateScene.tsx +++ /dev/null @@ -1,243 +0,0 @@ -import React, {useState} from 'react' -import * as Toast from '../util/Toast' -import { - ActivityIndicator, - StyleSheet, - TouchableOpacity, - View, -} from 'react-native' -import LinearGradient from 'react-native-linear-gradient' -import {BottomSheetScrollView, BottomSheetTextInput} from '@gorhom/bottom-sheet' -import {AppBskyActorCreateScene} from '@atproto/api' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {Text} from '../util/text/Text' -import {useStores} from '../../../state' -import {s, colors, gradients} from '../../lib/styles' -import { - makeValidHandle, - createFullHandle, - enforceLen, - MAX_DISPLAY_NAME, - MAX_DESCRIPTION, -} from '../../../lib/strings' - -export const snapPoints = ['60%'] - -export function Component({}: {}) { - const store = useStores() - const [error, setError] = useState('') - const [isProcessing, setIsProcessing] = useState(false) - const [handle, setHandle] = useState('') - const [displayName, setDisplayName] = useState('') - const [description, setDescription] = useState('') - const onPressSave = async () => { - setIsProcessing(true) - if (error) { - setError('') - } - try { - if (!store.me.did) { - return - } - const desc = await store.api.com.atproto.server.getAccountsConfig() - const fullHandle = createFullHandle( - handle, - desc.data.availableUserDomains[0], - ) - // create scene actor - const createSceneRes = await store.api.app.bsky.actor.createScene({ - handle: fullHandle, - }) - // set the scene profile - await store.api.app.bsky.actor - .updateProfile({ - did: createSceneRes.data.did, - displayName, - description, - }) - .catch(e => - // an error here is not critical - store.log.error('Failed to update scene profile during creation', e), - ) - // follow the scene - await store.api.app.bsky.graph.follow - .create( - { - did: store.me.did, - }, - { - subject: { - did: createSceneRes.data.did, - declarationCid: createSceneRes.data.declaration.cid, - }, - createdAt: new Date().toISOString(), - }, - ) - .catch(e => - // an error here is not critical - store.log.error('Failed to follow scene after creation', e), - ) - Toast.show('Scene created') - store.shell.closeModal() - store.nav.navigate(`/profile/${fullHandle}`) - } catch (e: any) { - if (e instanceof AppBskyActorCreateScene.InvalidHandleError) { - setError( - 'The handle can only contain letters, numbers, and dashes, and must start with a letter.', - ) - } else if (e instanceof AppBskyActorCreateScene.HandleNotAvailableError) { - setError(`The handle "${handle}" is not available.`) - } else { - store.log.error('Failed to create scene', e) - setError( - 'Failed to create the scene. Check your internet connection and try again.', - ) - } - setIsProcessing(false) - } - } - const onPressCancel = () => { - store.shell.closeModal() - } - - return ( - - - Create a scene - - Scenes are invite-only groups which aggregate what's popular with - members. - - - - Scene Handle - setHandle(makeValidHandle(str))} - /> - - - Scene Display Name - - setDisplayName(enforceLen(v, MAX_DISPLAY_NAME)) - } - /> - - - Scene Description - setDescription(enforceLen(v, MAX_DESCRIPTION))} - /> - - {error !== '' && ( - - - - )} - {handle.length >= 2 && !isProcessing ? ( - - - Create Scene - - - ) : ( - - - {isProcessing ? ( - - ) : ( - Create Scene - )} - - - )} - - - Cancel - - - - - - ) -} - -const styles = StyleSheet.create({ - outer: { - flex: 1, - // paddingTop: 20, - }, - title: { - textAlign: 'center', - fontWeight: 'bold', - fontSize: 24, - marginBottom: 12, - }, - description: { - textAlign: 'center', - fontSize: 17, - paddingHorizontal: 22, - color: colors.gray5, - marginBottom: 10, - }, - inner: { - padding: 14, - height: 350, - }, - group: { - marginBottom: 10, - }, - label: { - fontSize: 16, - fontWeight: 'bold', - paddingHorizontal: 4, - paddingBottom: 4, - }, - textInput: { - borderWidth: 1, - borderColor: colors.gray3, - borderRadius: 6, - paddingHorizontal: 14, - paddingVertical: 10, - fontSize: 16, - color: colors.black, - }, - textArea: { - borderWidth: 1, - borderColor: colors.gray3, - borderRadius: 6, - paddingHorizontal: 12, - paddingTop: 10, - fontSize: 16, - color: colors.black, - height: 70, - textAlignVertical: 'top', - }, - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - width: '100%', - borderRadius: 32, - padding: 14, - backgroundColor: colors.gray1, - }, -}) diff --git a/src/view/com/modals/InviteToScene.tsx b/src/view/com/modals/InviteToScene.tsx deleted file mode 100644 index 2b4d0ac2..00000000 --- a/src/view/com/modals/InviteToScene.tsx +++ /dev/null @@ -1,308 +0,0 @@ -import React, {useState, useEffect, useMemo} from 'react' -import {observer} from 'mobx-react-lite' -import * as Toast from '../util/Toast' -import { - ActivityIndicator, - FlatList, - StyleSheet, - useWindowDimensions, - View, -} from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import { - TabView, - SceneMap, - Route, - TabBar, - TabBarProps, -} from 'react-native-tab-view' -import _omit from 'lodash.omit' -import {AtUri} from '../../../third-party/uri' -import {ProfileCard} from '../profile/ProfileCard' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {Text} from '../util/text/Text' -import {useStores} from '../../../state' -import * as apilib from '../../../state/lib/api' -import {ProfileViewModel} from '../../../state/models/profile-view' -import {SuggestedInvitesView} from '../../../state/models/suggested-invites-view' -import {Assertion} from '../../../state/models/get-assertions-view' -import {FollowItem} from '../../../state/models/user-follows-view' -import {s, colors} from '../../lib/styles' - -export const snapPoints = ['70%'] - -export const Component = observer(function Component({ - profileView, -}: { - profileView: ProfileViewModel -}) { - const store = useStores() - const layout = useWindowDimensions() - const [index, setIndex] = useState(0) - const tabRoutes = [ - {key: 'suggestions', title: 'Suggestions'}, - {key: 'pending', title: 'Pending Invites'}, - ] - const [hasSetup, setHasSetup] = useState(false) - const [error, setError] = useState('') - const suggestions = useMemo( - () => new SuggestedInvitesView(store, {sceneDid: profileView.did}), - [profileView.did], - ) - const [createdInvites, setCreatedInvites] = useState>( - {}, - ) - // TODO: it would be much better if we just used the suggestions view for the deleted pending invites - // but mobx isnt picking up on the state change in suggestions.unconfirmed and I dont have - // time to debug that right now -prf - const [deletedPendingInvites, setDeletedPendingInvites] = useState< - Record - >({}) - - useEffect(() => { - let aborted = false - if (hasSetup) { - return - } - suggestions.setup().then(() => { - if (aborted) return - setHasSetup(true) - }) - return () => { - aborted = true - } - }, [profileView.did]) - - const onPressInvite = async (follow: FollowItem) => { - setError('') - try { - const assertionUri = await apilib.inviteToScene( - store, - profileView.did, - follow.did, - follow.declaration.cid, - ) - setCreatedInvites({[follow.did]: assertionUri, ...createdInvites}) - Toast.show('Invite sent') - } catch (e: any) { - setError('There was an issue with the invite. Please try again.') - store.log.error('Failed to invite user to scene', e) - } - } - const onPressUndo = async (subjectDid: string, assertionUri: string) => { - setError('') - const urip = new AtUri(assertionUri) - try { - await store.api.app.bsky.graph.assertion.delete({ - did: profileView.did, - rkey: urip.rkey, - }) - setCreatedInvites(_omit(createdInvites, [subjectDid])) - } catch (e: any) { - setError('There was an issue with the invite. Please try again.') - store.log.error('Failed to delete a scene invite', e) - } - } - - const onPressDeleteInvite = async (assertion: Assertion) => { - setError('') - const urip = new AtUri(assertion.uri) - try { - await store.api.app.bsky.graph.assertion.delete({ - did: profileView.did, - rkey: urip.rkey, - }) - setDeletedPendingInvites({ - [assertion.uri]: true, - ...deletedPendingInvites, - }) - Toast.show('Invite removed') - } catch (e: any) { - setError('There was an issue with the invite. Please try again.') - store.log.error('Failed to delete an invite', e) - } - } - - const renderSuggestionItem = ({item}: {item: FollowItem}) => { - const createdInvite = createdInvites[item.did] - return ( - - !createdInvite ? ( - <> - - Invite - - ) : ( - <> - - Undo invite - - ) - } - onPressButton={() => - !createdInvite - ? onPressInvite(item) - : onPressUndo(item.did, createdInvite) - } - /> - ) - } - - const renderPendingInviteItem = ({item}: {item: Assertion}) => { - const wasDeleted = deletedPendingInvites[item.uri] - if (wasDeleted) { - return - } - return ( - ( - <> - - Undo invite - - )} - onPressButton={() => onPressDeleteInvite(item)} - /> - ) - } - - const Suggestions = () => ( - - {hasSetup ? ( - - - - User search is still being implemented. For now, you can pick from - your follows below. - - - {!suggestions.hasContent ? ( - - {suggestions.myFollowsView.follows.length - ? 'Sorry! You dont follow anybody for us to suggest.' - : 'Sorry! All of the users you follow are members already.'} - - ) : ( - item._reactKey} - renderItem={renderSuggestionItem} - style={s.flex1} - /> - )} - - ) : !error ? ( - - ) : undefined} - - ) - - const PendingInvites = () => ( - - {suggestions.sceneAssertionsView.isLoading ? ( - - ) : undefined} - - {!suggestions.unconfirmed.length ? ( - - No pending invites. - - ) : ( - item._reactKey} - renderItem={renderPendingInviteItem} - style={s.flex1} - /> - )} - - - ) - - const renderScene = SceneMap({ - suggestions: Suggestions, - pending: PendingInvites, - }) - - const renderTabBar = (props: TabBarProps) => ( - - ) - - return ( - - - Invite to {profileView.displayName || profileView.handle} - - {error !== '' ? ( - - - - ) : undefined} - - - ) -}) - -const styles = StyleSheet.create({ - title: { - textAlign: 'center', - fontWeight: 'bold', - fontSize: 18, - marginBottom: 4, - }, - todoContainer: { - backgroundColor: colors.pink1, - margin: 10, - padding: 10, - borderRadius: 6, - }, - todoLabel: { - color: colors.pink5, - textAlign: 'center', - }, - - tabBar: { - flexDirection: 'row', - }, - tabItem: { - alignItems: 'center', - padding: 16, - flex: 1, - }, -}) diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index 43271c96..e0e18d54 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -9,8 +9,6 @@ import * as models from '../../../state/models/shell-ui' import * as ConfirmModal from './Confirm' import * as EditProfileModal from './EditProfile' -import * as CreateSceneModal from './CreateScene' -import * as InviteToSceneModal from './InviteToScene' import * as ServerInputModal from './ServerInput' import * as ReportPostModal from './ReportPost' import * as ReportAccountModal from './ReportAccount' @@ -55,16 +53,6 @@ export const Modal = observer(function Modal() { {...(store.shell.activeModal as models.EditProfileModal)} /> ) - } else if (store.shell.activeModal?.name === 'create-scene') { - snapPoints = CreateSceneModal.snapPoints - element = - } else if (store.shell.activeModal?.name === 'invite-to-scene') { - snapPoints = InviteToSceneModal.snapPoints - element = ( - - ) } else if (store.shell.activeModal?.name === 'server-input') { snapPoints = ServerInputModal.snapPoints element = ( diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx index c578b712..73948785 100644 --- a/src/view/com/notifications/FeedItem.tsx +++ b/src/view/com/notifications/FeedItem.tsx @@ -14,7 +14,6 @@ import {UserAvatar} from '../util/UserAvatar' import {ErrorMessage} from '../util/error/ErrorMessage' import {Post} from '../post/Post' import {Link} from '../util/Link' -import {InviteAccepter} from './InviteAccepter' import {usePalette} from '../../lib/hooks/usePalette' const MAX_AUTHORS = 8 @@ -26,7 +25,7 @@ export const FeedItem = observer(function FeedItem({ }) { const pal = usePalette('default') const itemHref = useMemo(() => { - if (item.isUpvote || item.isRepost || item.isTrend) { + if (item.isUpvote || item.isRepost) { const urip = new AtUri(item.subjectUri) return `/profile/${urip.host}/post/${urip.rkey}` } else if (item.isFollow || item.isAssertion) { @@ -82,10 +81,6 @@ export const FeedItem = observer(function FeedItem({ action = 'reposted your post' icon = 'retweet' iconStyle = [s.green3] - } else if (item.isTrend) { - action = 'Your post is trending with' - icon = 'arrow-trend-up' - iconStyle = [s.red3] } else if (item.isReply) { action = 'replied to your post' icon = ['far', 'comment'] @@ -93,10 +88,6 @@ export const FeedItem = observer(function FeedItem({ action = 'followed you' icon = 'user-plus' iconStyle = [s.blue3] - } else if (item.isInvite) { - icon = 'users' - iconStyle = [s.blue3] - action = 'invited you to join their scene' } else { return <> } @@ -173,9 +164,6 @@ export const FeedItem = observer(function FeedItem({ ) : undefined} - {item.isTrend && ( - {action} - )} ) : undefined} - {!item.isTrend && ( - {action} - )} {ago(item.indexedAt)} - {item.isUpvote || item.isRepost || item.isTrend ? ( + {item.isUpvote || item.isRepost ? ( ) : ( <> )} - {item.isInvite && ( - - - - )} ) }) diff --git a/src/view/com/notifications/InviteAccepter.tsx b/src/view/com/notifications/InviteAccepter.tsx deleted file mode 100644 index a8789b17..00000000 --- a/src/view/com/notifications/InviteAccepter.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react' -import {StyleSheet, TouchableOpacity, View} from 'react-native' -import LinearGradient from 'react-native-linear-gradient' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import * as apilib from '../../../state/lib/api' -import {NotificationsViewItemModel} from '../../../state/models/notifications-view' -import {ConfirmModal} from '../../../state/models/shell-ui' -import {useStores} from '../../../state' -import {ProfileCard} from '../profile/ProfileCard' -import * as Toast from '../util/Toast' -import {Text} from '../util/text/Text' -import {s, colors, gradients} from '../../lib/styles' - -export function InviteAccepter({item}: {item: NotificationsViewItemModel}) { - const store = useStores() - // Using default import (React.use...) instead of named import (use...) to be able to mock store's data in jest environment - const [confirmationUri, setConfirmationUri] = React.useState('') - const isMember = - confirmationUri !== '' || store.me.memberships?.isMemberOf(item.author.did) - const onPressAccept = async () => { - store.shell.openModal( - new ConfirmModal( - 'Join this scene?', - () => ( - - - - - - ), - onPressConfirmAccept, - ), - ) - } - const onPressConfirmAccept = async () => { - const uri = await apilib.acceptSceneInvite(store, { - originator: { - did: item.author.did, - declarationCid: item.author.declaration.cid, - }, - assertion: { - uri: item.uri, - cid: item.cid, - }, - }) - store.me.refreshMemberships() - Toast.show('Invite accepted') - setConfirmationUri(uri) - } - return ( - - {!isMember ? ( - - - Accept Invite - - - ) : ( - - - Invite accepted - - )} - - ) -} - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - }, - btn: { - borderRadius: 32, - paddingHorizontal: 18, - paddingVertical: 8, - backgroundColor: colors.gray1, - }, - profileCardContainer: { - borderWidth: 1, - borderColor: colors.gray3, - borderRadius: 6, - }, - inviteAccepted: { - flexDirection: 'row', - alignItems: 'center', - }, -}) diff --git a/src/view/com/onboard/FeatureExplainer.tsx b/src/view/com/onboard/FeatureExplainer.tsx index ecc1b969..78ace518 100644 --- a/src/view/com/onboard/FeatureExplainer.tsx +++ b/src/view/com/onboard/FeatureExplainer.tsx @@ -11,10 +11,9 @@ import { import {TabView, SceneMap, Route, TabBarProps} from 'react-native-tab-view' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {Text} from '../util/text/Text' -import {UserGroupIcon} from '../../lib/icons' import {useStores} from '../../../state' import {s} from '../../lib/styles' -import {SCENE_EXPLAINER, TABS_EXPLAINER} from '../../lib/assets' +import {TABS_EXPLAINER} from '../../lib/assets' import {TABS_ENABLED} from '../../../build-flags' const Intro = () => ( @@ -28,25 +27,7 @@ const Intro = () => ( Welcome to Bluesky - Let's do a quick tour through the new features. - - -) - -const Scenes = () => ( - - - - - - - Scenes - - Scenes are invite-only groups of users. Follow them to see what's trending - with the scene's members. - - - + This is an early beta. Your feedback is appreciated! ) @@ -74,7 +55,6 @@ const Tabs = () => ( const SCENE_MAP = { intro: Intro, - scenes: Scenes, tabs: Tabs, } const renderScene = SceneMap(SCENE_MAP) @@ -85,7 +65,6 @@ export const FeatureExplainer = () => { const [index, setIndex] = useState(0) const routes = [ {key: 'intro', title: 'Intro'}, - {key: 'scenes', title: 'Scenes'}, TABS_ENABLED ? {key: 'tabs', title: 'Tabs'} : undefined, ].filter(Boolean) diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index 80e08ae7..f5536907 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -155,23 +155,6 @@ export const FeedItem = observer(function ({ )} - {item.reasonTrend && ( - - - - Trending with{' '} - {item.reasonTrend.by.displayName || item.reasonTrend.by.handle} - - - )} diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 4fd76695..663290a2 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -1,15 +1,12 @@ -import React, {useMemo} from 'react' +import React from 'react' import {observer} from 'mobx-react-lite' import {StyleSheet, TouchableOpacity, View} from 'react-native' import LinearGradient from 'react-native-linear-gradient' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {AtUri} from '../../../third-party/uri' import {ProfileViewModel} from '../../../state/models/profile-view' import {useStores} from '../../../state' import { - ConfirmModal, EditProfileModal, - InviteToSceneModal, ReportAccountModal, ProfileImageLightbox, } from '../../../state/models/shell-ui' @@ -23,7 +20,6 @@ import {Text} from '../util/text/Text' import {RichText} from '../util/text/RichText' import {UserAvatar} from '../util/UserAvatar' import {UserBanner} from '../util/UserBanner' -import {UserInfoText} from '../util/UserInfoText' import {usePalette} from '../../lib/hooks/usePalette' export const ProfileHeader = observer(function ProfileHeader({ @@ -35,10 +31,6 @@ export const ProfileHeader = observer(function ProfileHeader({ }) { const pal = usePalette('default') const store = useStores() - const isMember = useMemo( - () => view.isScene && view.myState.member, - [view.myState.member], - ) const onPressAvi = () => { store.shell.openLightbox(new ProfileImageLightbox(view)) @@ -64,31 +56,6 @@ export const ProfileHeader = observer(function ProfileHeader({ const onPressFollows = () => { store.nav.navigate(`/profile/${view.handle}/follows`) } - const onPressMembers = () => { - store.nav.navigate(`/profile/${view.handle}/members`) - } - const onPressInviteMembers = () => { - store.shell.openModal(new InviteToSceneModal(view)) - } - const onPressLeaveScene = () => { - store.shell.openModal( - new ConfirmModal( - 'Leave this scene?', - `You'll be able to come back unless your invite is revoked.`, - onPressConfirmLeaveScene, - ), - ) - } - const onPressConfirmLeaveScene = async () => { - if (view.myState.member) { - await store.api.app.bsky.graph.confirmation.delete({ - did: store.me.did || '', - rkey: new AtUri(view.myState.member).rkey, - }) - Toast.show(`Scene left`) - } - onRefreshAll() - } const onPressMuteAccount = async () => { try { await view.muteAccount() @@ -157,7 +124,6 @@ export const ProfileHeader = observer(function ProfileHeader({ // = const gradient = getGradient(view.handle) const isMe = store.me.did === view.did - const isCreator = view.isScene && view.creator === store.me.did let dropdownItems: DropdownItem[] | undefined if (!isMe) { dropdownItems = dropdownItems || [] @@ -170,21 +136,6 @@ export const ProfileHeader = observer(function ProfileHeader({ onPress: onPressReportAccount, }) } - if (isCreator || isMember) { - dropdownItems = dropdownItems || [] - if (isCreator) { - dropdownItems.push({ - label: 'Edit Profile', - onPress: onPressEditProfile, - }) - } - if (isMember) { - dropdownItems.push({ - label: 'Leave Scene...', - onPress: onPressLeaveScene, - }) - } - } return ( @@ -247,15 +198,6 @@ export const ProfileHeader = observer(function ProfileHeader({ - {view.isScene ? ( - - Scene - - ) : undefined} @{view.handle} @@ -283,19 +225,6 @@ export const ProfileHeader = observer(function ProfileHeader({ ) : undefined} - {view.isScene ? ( - - - {view.membersCount} - - - {pluralize(view.membersCount, 'member')} - - - ) : undefined} {view.postsCount} @@ -313,35 +242,6 @@ export const ProfileHeader = observer(function ProfileHeader({ entities={view.descriptionEntities} /> ) : undefined} - {view.isScene && view.creator ? ( - - - - Created by - - - - ) : undefined} - {view.isScene && view.myState.member ? ( - - - - You are a member - - - ) : undefined} {view.myState.muted ? ( ) : undefined} - {view.isScene && view.creator === store.me.did ? ( - - - - - - Invite Members - - - - - ) : undefined} () - - useEffect(() => { - if (view?.params.actor === name) { - return // no change needed? or trigger refresh? - } - const newView = new MembersViewModel(store, {actor: name}) - setView(newView) - newView - .setup() - .catch(err => store.log.error('Failed to fetch members', err)) - }, [name, view?.params.actor, store]) - - const onRefresh = () => { - view?.refresh() - } - - // loading - // = - if ( - !view || - (view.isLoading && !view.isRefreshing) || - view.params.actor !== name - ) { - return ( - - - - ) - } - - // error - // = - if (view.hasError) { - return ( - - - - ) - } - - // loaded - // = - const renderItem = ({item}: {item: MemberItem}) => ( - - ) - return ( - - item._reactKey} - renderItem={renderItem} - /> - - ) -}) diff --git a/src/view/index.ts b/src/view/index.ts index 5602784f..8ffd5957 100644 --- a/src/view/index.ts +++ b/src/view/index.ts @@ -12,7 +12,6 @@ import {faArrowRightFromBracket} from '@fortawesome/free-solid-svg-icons' import {faArrowUpFromBracket} from '@fortawesome/free-solid-svg-icons/faArrowUpFromBracket' import {faArrowUpRightFromSquare} from '@fortawesome/free-solid-svg-icons/faArrowUpRightFromSquare' import {faArrowsRotate} from '@fortawesome/free-solid-svg-icons/faArrowsRotate' -import {faArrowTrendUp} from '@fortawesome/free-solid-svg-icons/faArrowTrendUp' import {faAt} from '@fortawesome/free-solid-svg-icons/faAt' import {faBars} from '@fortawesome/free-solid-svg-icons/faBars' import {faBell} from '@fortawesome/free-solid-svg-icons/faBell' @@ -81,7 +80,6 @@ export function setup() { faArrowUpFromBracket, faArrowUpRightFromSquare, faArrowsRotate, - faArrowTrendUp, faAt, faBars, faBell, diff --git a/src/view/lib/assets.native.ts b/src/view/lib/assets.native.ts index 4b5c3efc..609f8e01 100644 --- a/src/view/lib/assets.native.ts +++ b/src/view/lib/assets.native.ts @@ -1,5 +1,4 @@ import {ImageSourcePropType} from 'react-native' export const DEF_AVATAR: ImageSourcePropType = require('../../../public/img/default-avatar.jpg') -export const SCENE_EXPLAINER: ImageSourcePropType = require('../../../public/img/scene-explainer.jpg') export const TABS_EXPLAINER: ImageSourcePropType = require('../../../public/img/tabs-explainer.jpg') diff --git a/src/view/lib/assets.ts b/src/view/lib/assets.ts index 04c36808..9e937d4d 100644 --- a/src/view/lib/assets.ts +++ b/src/view/lib/assets.ts @@ -1,9 +1,6 @@ import {ImageSourcePropType} from 'react-native' export const DEF_AVATAR: ImageSourcePropType = {uri: '/img/default-avatar.jpg'} -export const SCENE_EXPLAINER: ImageSourcePropType = { - uri: '/img/scene-explainer.jpg', -} export const TABS_EXPLAINER: ImageSourcePropType = { uri: '/img/tabs-explainer.jpg', } diff --git a/src/view/routes.ts b/src/view/routes.ts index 0a2883e6..7d5a06ac 100644 --- a/src/view/routes.ts +++ b/src/view/routes.ts @@ -13,7 +13,6 @@ import {PostRepostedBy} from './screens/PostRepostedBy' import {Profile} from './screens/Profile' import {ProfileFollowers} from './screens/ProfileFollowers' import {ProfileFollows} from './screens/ProfileFollows' -import {ProfileMembers} from './screens/ProfileMembers' import {Settings} from './screens/Settings' import {Debug} from './screens/Debug' import {Log} from './screens/Log' @@ -48,7 +47,6 @@ export const routes: Route[] = [ r('/profile/(?[^/]+)/followers'), ], [ProfileFollows, 'Follows', 'users', r('/profile/(?[^/]+)/follows')], - [ProfileMembers, 'Members', 'users', r('/profile/(?[^/]+)/members')], [ PostThread, 'Post', diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx index 7c9fac40..dd6e0761 100644 --- a/src/view/screens/Notifications.tsx +++ b/src/view/screens/Notifications.tsx @@ -15,7 +15,6 @@ export const Notifications = ({navIdx, visible}: ScreenParams) => { return } store.log.debug('Updating notifications feed') - store.me.refreshMemberships() // needed for the invite notifications store.me.notifications .update() .catch(e => { diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 64bb4f04..454ae8ad 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -1,16 +1,13 @@ import React, {useEffect, useState} from 'react' import {ActivityIndicator, StyleSheet, View} from 'react-native' import {observer} from 'mobx-react-lite' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {ViewSelector} from '../com/util/ViewSelector' import {ScreenParams} from '../routes' import {ProfileUiModel, Sections} from '../../state/models/profile-ui' -import {MembershipItem} from '../../state/models/memberships-view' import {useStores} from '../../state' import {ConfirmModal} from '../../state/models/shell-ui' import {ProfileHeader} from '../com/profile/ProfileHeader' import {FeedItem} from '../com/posts/FeedItem' -import {ProfileCard} from '../com/profile/ProfileCard' import {PostFeedLoadingPlaceholder} from '../com/util/LoadingPlaceholder' import {ErrorScreen} from '../com/util/error/ErrorScreen' import {ErrorMessage} from '../com/util/error/ErrorMessage' @@ -77,18 +74,6 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => { const onPressTryAgain = () => { uiState.setup() } - const onPressRemoveMember = (membership: MembershipItem) => { - store.shell.openModal( - new ConfirmModal( - `Remove ${membership.displayName || membership.handle}?`, - `You'll be able to invite them again if you change your mind.`, - async () => { - await uiState.members.removeMember(membership.did) - Toast.show(`User removed`) - }, - ), - ) - } const onPressCompose = () => { store.shell.openComposer({}) @@ -97,9 +82,6 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => { // rendering // = - const isSceneCreator = - uiState.isScene && store.me.did === uiState.profile.creator - const renderHeader = () => { if (!uiState) { return @@ -131,8 +113,7 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => { } else { if ( uiState.selectedView === Sections.Posts || - uiState.selectedView === Sections.PostsWithReplies || - uiState.selectedView === Sections.Trending + uiState.selectedView === Sections.PostsWithReplies ) { if (uiState.feed.hasContent) { if (uiState.selectedView === Sections.Posts) { @@ -152,81 +133,12 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => { return } } else if (uiState.feed.isEmpty) { - items = items.concat([EMPTY_ITEM]) - if (uiState.profile.isScene) { - renderItem = () => ( - - ) - } else { - renderItem = () => ( - - ) - } - } - } else if (uiState.selectedView === Sections.Scenes) { - if (uiState.memberships.hasContent) { - items = uiState.memberships.memberships.slice() - renderItem = (item: any) => { - return ( - - ) - } - } else if (uiState.memberships.isEmpty) { items = items.concat([EMPTY_ITEM]) renderItem = () => ( - ) - } - } else if (uiState.selectedView === Sections.Members) { - if (uiState.members.hasContent) { - items = uiState.members.members.slice() - renderItem = (item: any) => { - const shouldAdmin = isSceneCreator && item.did !== store.me.did - const renderButton = shouldAdmin - ? () => ( - <> - - Remove - - ) - : undefined - return ( - onPressRemoveMember(item)} - /> - ) - } - } else if (uiState.members.isEmpty) { - items = items.concat([EMPTY_ITEM]) - renderItem = () => ( - ) } diff --git a/src/view/screens/ProfileMembers.tsx b/src/view/screens/ProfileMembers.tsx deleted file mode 100644 index 9d6723fe..00000000 --- a/src/view/screens/ProfileMembers.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, {useEffect} from 'react' -import {View} from 'react-native' -import {ViewHeader} from '../com/util/ViewHeader' -import {ProfileMembers as ProfileMembersComponent} from '../com/profile/ProfileMembers' -import {ScreenParams} from '../routes' -import {useStores} from '../../state' - -export const ProfileMembers = ({navIdx, visible, params}: ScreenParams) => { - const store = useStores() - const {name} = params - - useEffect(() => { - if (visible) { - store.nav.setTitle(navIdx, `Members of ${name}`) - store.shell.setMinimalShellMode(false) - } - }, [store, visible, name]) - - return ( - - - - - ) -} diff --git a/src/view/shell/mobile/Menu.tsx b/src/view/shell/mobile/Menu.tsx index 6a673d25..3a6bbbc0 100644 --- a/src/view/shell/mobile/Menu.tsx +++ b/src/view/shell/mobile/Menu.tsx @@ -1,4 +1,4 @@ -import React, {useEffect} from 'react' +import React from 'react' import { ScrollView, StyleProp, @@ -11,17 +11,10 @@ import {observer} from 'mobx-react-lite' import VersionNumber from 'react-native-version-number' import {s, colors} from '../../lib/styles' import {useStores} from '../../../state' -import { - HomeIcon, - UserGroupIcon, - BellIcon, - CogIcon, - MagnifyingGlassIcon, -} from '../../lib/icons' +import {HomeIcon, BellIcon, CogIcon, MagnifyingGlassIcon} from '../../lib/icons' import {UserAvatar} from '../../com/util/UserAvatar' import {Text} from '../../com/util/text/Text' import {ToggleButton} from '../../com/util/forms/ToggleButton' -import {CreateSceneModal} from '../../../state/models/shell-ui' import {usePalette} from '../../lib/hooks/usePalette' export const Menu = observer( @@ -29,14 +22,6 @@ export const Menu = observer( const pal = usePalette('default') const store = useStores() - useEffect(() => { - if (visible) { - // trigger a refresh in case memberships have changed recently - // TODO this impacts performance, need to find the right time to do this - // store.me.refreshMemberships() - } - }, [store, visible]) - // events // = @@ -51,10 +36,6 @@ export const Menu = observer( } } } - const onPressCreateScene = () => { - onClose() - store.shell.openModal(new CreateSceneModal()) - } // rendering // = @@ -152,40 +133,6 @@ export const Menu = observer( url="/notifications" count={store.me.notificationCount} /> - - - - Scenes - - {store.me.memberships - ? store.me.memberships.memberships.map((membership, i) => ( - - } - label={membership.displayName || membership.handle} - url={`/profile/${membership.handle}`} - /> - )) - : undefined} - - - } - size="30" - /> - } - label="Create a scene" - onPress={onPressCreateScene} - />