about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-01-17 10:11:30 -0600
committerGitHub <noreply@github.com>2023-01-17 10:11:30 -0600
commitbf1092ad86ef8e5829db29a17f33380dabab8535 (patch)
tree5cf0d18a88d7162fcfe258aff89d3d868268d0d9 /src
parent5abcc8e336b3af11a6c98d0d9e662415856478a0 (diff)
downloadvoidsky-bf1092ad86ef8e5829db29a17f33380dabab8535.tar.zst
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
Diffstat (limited to 'src')
-rw-r--r--src/state/lib/api.ts48
-rw-r--r--src/state/models/feed-view.ts10
-rw-r--r--src/state/models/me.ts13
-rw-r--r--src/state/models/members-view.ts149
-rw-r--r--src/state/models/memberships-view.ts127
-rw-r--r--src/state/models/notifications-view.ts29
-rw-r--r--src/state/models/profile-ui.ts43
-rw-r--r--src/state/models/profile-view.ts8
-rw-r--r--src/state/models/shell-ui.ts18
-rw-r--r--src/state/models/suggested-invites-view.ts142
-rw-r--r--src/view/com/modals/CreateScene.tsx243
-rw-r--r--src/view/com/modals/InviteToScene.tsx308
-rw-r--r--src/view/com/modals/Modal.tsx12
-rw-r--r--src/view/com/notifications/FeedItem.tsx24
-rw-r--r--src/view/com/notifications/InviteAccepter.tsx96
-rw-r--r--src/view/com/onboard/FeatureExplainer.tsx25
-rw-r--r--src/view/com/posts/FeedItem.tsx17
-rw-r--r--src/view/com/profile/ProfileHeader.tsx143
-rw-r--r--src/view/com/profile/ProfileMembers.tsx80
-rw-r--r--src/view/index.ts2
-rw-r--r--src/view/lib/assets.native.ts1
-rw-r--r--src/view/lib/assets.ts3
-rw-r--r--src/view/routes.ts2
-rw-r--r--src/view/screens/Notifications.tsx1
-rw-r--r--src/view/screens/Profile.tsx96
-rw-r--r--src/view/screens/ProfileMembers.tsx25
-rw-r--r--src/view/shell/mobile/Menu.tsx57
27 files changed, 18 insertions, 1704 deletions
diff --git a/src/state/lib/api.ts b/src/state/lib/api.ts
index e701ae6f5..8dc9ce5f5 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<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>
diff --git a/src/state/models/feed-view.ts b/src/state/models/feed-view.ts
index 5f2b9721e..c39daf874 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 0ae52db8f..201ce04c7 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 73295f479..000000000
--- 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 661b3f6ae..000000000
--- 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 c169a995c..c4d2b2dfa 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 fb90fb694..55fb25061 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 2670627c3..a1535693c 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 52d081680..1af74f56a 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 fadc956cc..000000000
--- 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 d92fe2e31..000000000
--- 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<string>('')
-  const [isProcessing, setIsProcessing] = useState<boolean>(false)
-  const [handle, setHandle] = useState<string>('')
-  const [displayName, setDisplayName] = useState<string>('')
-  const [description, setDescription] = useState<string>('')
-  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 (
-    <View style={styles.outer}>
-      <BottomSheetScrollView style={styles.inner}>
-        <Text style={[styles.title, s.black]}>Create a scene</Text>
-        <Text style={styles.description}>
-          Scenes are invite-only groups which aggregate what's popular with
-          members.
-        </Text>
-        <View style={{paddingBottom: 50}}>
-          <View style={styles.group}>
-            <Text style={[styles.label, s.black]}>Scene Handle</Text>
-            <BottomSheetTextInput
-              style={styles.textInput}
-              placeholder="e.g. alices-friends"
-              placeholderTextColor={colors.gray4}
-              autoCorrect={false}
-              value={handle}
-              onChangeText={str => setHandle(makeValidHandle(str))}
-            />
-          </View>
-          <View style={styles.group}>
-            <Text style={[styles.label, s.black]}>Scene Display Name</Text>
-            <BottomSheetTextInput
-              style={styles.textInput}
-              placeholder="e.g. Alice's Friends"
-              placeholderTextColor={colors.gray4}
-              value={displayName}
-              onChangeText={v =>
-                setDisplayName(enforceLen(v, MAX_DISPLAY_NAME))
-              }
-            />
-          </View>
-          <View style={styles.group}>
-            <Text style={[styles.label, s.black]}>Scene Description</Text>
-            <BottomSheetTextInput
-              style={[styles.textArea]}
-              placeholder="e.g. Artists, dog-lovers, and memelords."
-              placeholderTextColor={colors.gray4}
-              multiline
-              value={description}
-              onChangeText={v => setDescription(enforceLen(v, MAX_DESCRIPTION))}
-            />
-          </View>
-          {error !== '' && (
-            <View style={s.mb10}>
-              <ErrorMessage message={error} numberOfLines={3} />
-            </View>
-          )}
-          {handle.length >= 2 && !isProcessing ? (
-            <TouchableOpacity style={s.mt10} onPress={onPressSave}>
-              <LinearGradient
-                colors={[gradients.primary.start, gradients.primary.end]}
-                start={{x: 0, y: 0}}
-                end={{x: 1, y: 1}}
-                style={[styles.btn]}>
-                <Text style={[s.white, s.bold, s.f18]}>Create Scene</Text>
-              </LinearGradient>
-            </TouchableOpacity>
-          ) : (
-            <View style={s.mt10}>
-              <View style={[styles.btn]}>
-                {isProcessing ? (
-                  <ActivityIndicator />
-                ) : (
-                  <Text style={[s.gray4, s.bold, s.f18]}>Create Scene</Text>
-                )}
-              </View>
-            </View>
-          )}
-          <TouchableOpacity style={s.mt10} onPress={onPressCancel}>
-            <View style={[styles.btn, {backgroundColor: colors.white}]}>
-              <Text style={[s.black, s.bold]}>Cancel</Text>
-            </View>
-          </TouchableOpacity>
-        </View>
-      </BottomSheetScrollView>
-    </View>
-  )
-}
-
-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 2b4d0ac29..000000000
--- 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<boolean>(false)
-  const [error, setError] = useState<string>('')
-  const suggestions = useMemo(
-    () => new SuggestedInvitesView(store, {sceneDid: profileView.did}),
-    [profileView.did],
-  )
-  const [createdInvites, setCreatedInvites] = useState<Record<string, string>>(
-    {},
-  )
-  // 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<string, boolean>
-  >({})
-
-  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 (
-      <ProfileCard
-        did={item.did}
-        handle={item.handle}
-        displayName={item.displayName}
-        avatar={item.avatar}
-        renderButton={() =>
-          !createdInvite ? (
-            <>
-              <FontAwesomeIcon icon="user-plus" style={[s.mr5]} size={14} />
-              <Text style={[s.fw400, s.f14]}>Invite</Text>
-            </>
-          ) : (
-            <>
-              <FontAwesomeIcon icon="x" style={[s.mr5]} size={14} />
-              <Text style={[s.fw400, s.f14]}>Undo invite</Text>
-            </>
-          )
-        }
-        onPressButton={() =>
-          !createdInvite
-            ? onPressInvite(item)
-            : onPressUndo(item.did, createdInvite)
-        }
-      />
-    )
-  }
-
-  const renderPendingInviteItem = ({item}: {item: Assertion}) => {
-    const wasDeleted = deletedPendingInvites[item.uri]
-    if (wasDeleted) {
-      return <View />
-    }
-    return (
-      <ProfileCard
-        did={item.subject.did}
-        handle={item.subject.handle}
-        displayName={item.subject.displayName}
-        avatar={item.subject.avatar}
-        renderButton={() => (
-          <>
-            <FontAwesomeIcon icon="x" style={[s.mr5]} size={14} />
-            <Text style={[s.fw400, s.f14]}>Undo invite</Text>
-          </>
-        )}
-        onPressButton={() => onPressDeleteInvite(item)}
-      />
-    )
-  }
-
-  const Suggestions = () => (
-    <View style={s.flex1}>
-      {hasSetup ? (
-        <View style={s.flex1}>
-          <View style={styles.todoContainer}>
-            <Text style={styles.todoLabel}>
-              User search is still being implemented. For now, you can pick from
-              your follows below.
-            </Text>
-          </View>
-          {!suggestions.hasContent ? (
-            <Text
-              style={{
-                textAlign: 'center',
-                paddingTop: 10,
-                paddingHorizontal: 40,
-                fontWeight: 'bold',
-                color: colors.gray5,
-              }}>
-              {suggestions.myFollowsView.follows.length
-                ? 'Sorry! You dont follow anybody for us to suggest.'
-                : 'Sorry! All of the users you follow are members already.'}
-            </Text>
-          ) : (
-            <FlatList
-              data={suggestions.suggestions}
-              keyExtractor={item => item._reactKey}
-              renderItem={renderSuggestionItem}
-              style={s.flex1}
-            />
-          )}
-        </View>
-      ) : !error ? (
-        <ActivityIndicator />
-      ) : undefined}
-    </View>
-  )
-
-  const PendingInvites = () => (
-    <View style={s.flex1}>
-      {suggestions.sceneAssertionsView.isLoading ? (
-        <ActivityIndicator />
-      ) : undefined}
-      <View style={s.flex1}>
-        {!suggestions.unconfirmed.length ? (
-          <Text
-            style={{
-              textAlign: 'center',
-              paddingTop: 10,
-              paddingHorizontal: 40,
-              fontWeight: 'bold',
-              color: colors.gray5,
-            }}>
-            No pending invites.
-          </Text>
-        ) : (
-          <FlatList
-            data={suggestions.unconfirmed}
-            keyExtractor={item => item._reactKey}
-            renderItem={renderPendingInviteItem}
-            style={s.flex1}
-          />
-        )}
-      </View>
-    </View>
-  )
-
-  const renderScene = SceneMap({
-    suggestions: Suggestions,
-    pending: PendingInvites,
-  })
-
-  const renderTabBar = (props: TabBarProps<Route>) => (
-    <TabBar
-      {...props}
-      style={{backgroundColor: 'white'}}
-      activeColor="black"
-      inactiveColor={colors.gray5}
-      labelStyle={{textTransform: 'none'}}
-      indicatorStyle={{backgroundColor: colors.purple3}}
-    />
-  )
-
-  return (
-    <View style={s.flex1}>
-      <Text style={styles.title}>
-        Invite to {profileView.displayName || profileView.handle}
-      </Text>
-      {error !== '' ? (
-        <View style={s.p10}>
-          <ErrorMessage message={error} />
-        </View>
-      ) : undefined}
-      <TabView
-        navigationState={{index, routes: tabRoutes}}
-        renderScene={renderScene}
-        renderTabBar={renderTabBar}
-        onIndexChange={setIndex}
-        initialLayout={{width: layout.width}}
-      />
-    </View>
-  )
-})
-
-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 43271c964..e0e18d54a 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 = <CreateSceneModal.Component />
-  } else if (store.shell.activeModal?.name === 'invite-to-scene') {
-    snapPoints = InviteToSceneModal.snapPoints
-    element = (
-      <InviteToSceneModal.Component
-        {...(store.shell.activeModal as models.InviteToSceneModal)}
-      />
-    )
   } 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 c578b7120..739487859 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}
           </View>
           <View style={styles.meta}>
-            {item.isTrend && (
-              <Text style={[styles.metaItem, pal.text]}>{action}</Text>
-            )}
             <Link
               key={authors[0].href}
               style={styles.metaItem}
@@ -193,25 +181,17 @@ export const FeedItem = observer(function FeedItem({
                 </Text>
               </>
             ) : undefined}
-            {!item.isTrend && (
-              <Text style={[styles.metaItem, pal.text]}>{action}</Text>
-            )}
             <Text style={[styles.metaItem, pal.textLight]}>
               {ago(item.indexedAt)}
             </Text>
           </View>
-          {item.isUpvote || item.isRepost || item.isTrend ? (
+          {item.isUpvote || item.isRepost ? (
             <AdditionalPostText additionalPost={item.additionalPost} />
           ) : (
             <></>
           )}
         </View>
       </View>
-      {item.isInvite && (
-        <View style={styles.addedContainer}>
-          <InviteAccepter item={item} />
-        </View>
-      )}
     </Link>
   )
 })
diff --git a/src/view/com/notifications/InviteAccepter.tsx b/src/view/com/notifications/InviteAccepter.tsx
deleted file mode 100644
index a8789b171..000000000
--- 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<string>('')
-  const isMember =
-    confirmationUri !== '' || store.me.memberships?.isMemberOf(item.author.did)
-  const onPressAccept = async () => {
-    store.shell.openModal(
-      new ConfirmModal(
-        'Join this scene?',
-        () => (
-          <View>
-            <View style={styles.profileCardContainer}>
-              <ProfileCard
-                did={item.author.did}
-                handle={item.author.handle}
-                displayName={item.author.displayName}
-                avatar={item.author.avatar}
-              />
-            </View>
-          </View>
-        ),
-        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 (
-    <View style={styles.container}>
-      {!isMember ? (
-        <TouchableOpacity testID="acceptInviteButton" onPress={onPressAccept}>
-          <LinearGradient
-            colors={[gradients.primary.start, gradients.primary.end]}
-            start={{x: 0, y: 0}}
-            end={{x: 1, y: 1}}
-            style={[styles.btn]}>
-            <Text style={[s.white, s.bold, s.f16]}>Accept Invite</Text>
-          </LinearGradient>
-        </TouchableOpacity>
-      ) : (
-        <View testID="inviteAccepted" style={styles.inviteAccepted}>
-          <FontAwesomeIcon icon="check" size={14} style={s.mr5} />
-          <Text style={[s.gray5, s.f15]}>Invite accepted</Text>
-        </View>
-      )}
-    </View>
-  )
-}
-
-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 ecc1b9692..78ace5189 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 <Text style={[s.bold, s.blue3, {fontSize: 56}]}>Bluesky</Text>
     </Text>
     <Text style={[styles.explainerDesc, {fontSize: 24}]}>
-      Let's do a quick tour through the new features.
-    </Text>
-  </View>
-)
-
-const Scenes = () => (
-  <View style={styles.explainer}>
-    <View style={styles.explainerIcon}>
-      <View style={s.flex1} />
-      <UserGroupIcon style={s.black} size="48" />
-      <View style={s.flex1} />
-    </View>
-    <Text style={styles.explainerHeading}>Scenes</Text>
-    <Text style={styles.explainerDesc}>
-      Scenes are invite-only groups of users. Follow them to see what's trending
-      with the scene's members.
-    </Text>
-    <Text style={styles.explainerDesc}>
-      <Image source={SCENE_EXPLAINER} style={styles.explainerImg} />
+      This is an early beta. Your feedback is appreciated!
     </Text>
   </View>
 )
@@ -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 80e08ae75..f5536907d 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -155,23 +155,6 @@ export const FeedItem = observer(function ({
             </Text>
           </Link>
         )}
-        {item.reasonTrend && (
-          <Link
-            style={styles.includeReason}
-            href={`/profile/${item.reasonTrend.by.handle}`}
-            title={
-              item.reasonTrend.by.displayName || item.reasonTrend.by.handle
-            }>
-            <FontAwesomeIcon
-              icon="arrow-trend-up"
-              style={styles.includeReasonIcon}
-            />
-            <Text type="overline2" style={{color: pal.colors.actionLabel}}>
-              Trending with{' '}
-              {item.reasonTrend.by.displayName || item.reasonTrend.by.handle}
-            </Text>
-          </Link>
-        )}
         <View style={styles.layout}>
           <View style={styles.layoutAvi}>
             <Link href={authorHref} title={item.post.author.handle}>
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index 4fd766952..663290a2b 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 (
     <View style={pal.view}>
       <UserBanner handle={view.handle} banner={view.banner} />
@@ -247,15 +198,6 @@ export const ProfileHeader = observer(function ProfileHeader({
           </Text>
         </View>
         <View style={styles.handleLine}>
-          {view.isScene ? (
-            <View
-              style={[
-                styles.typeLabelWrapper,
-                {backgroundColor: pal.colors.backgroundLight},
-              ]}>
-              <Text style={[styles.typeLabel, pal.textLight]}>Scene</Text>
-            </View>
-          ) : undefined}
           <Text style={pal.textLight}>@{view.handle}</Text>
         </View>
         <View style={styles.metricsLine}>
@@ -283,19 +225,6 @@ export const ProfileHeader = observer(function ProfileHeader({
               </Text>
             </TouchableOpacity>
           ) : undefined}
-          {view.isScene ? (
-            <TouchableOpacity
-              testID="profileHeaderMembersButton"
-              style={[s.flexRow, s.mr10]}
-              onPress={onPressMembers}>
-              <Text type="body2" style={[s.bold, s.mr2, pal.text]}>
-                {view.membersCount}
-              </Text>
-              <Text type="body2" style={[pal.textLight]}>
-                {pluralize(view.membersCount, 'member')}
-              </Text>
-            </TouchableOpacity>
-          ) : undefined}
           <View style={[s.flexRow, s.mr10]}>
             <Text type="body2" style={[s.bold, s.mr2, pal.text]}>
               {view.postsCount}
@@ -313,35 +242,6 @@ export const ProfileHeader = observer(function ProfileHeader({
             entities={view.descriptionEntities}
           />
         ) : undefined}
-        {view.isScene && view.creator ? (
-          <View style={styles.detailLine}>
-            <FontAwesomeIcon
-              icon={['far', 'user']}
-              style={[pal.textLight, s.mr5]}
-            />
-            <Text type="body2" style={[s.mr2, pal.textLight]}>
-              Created by
-            </Text>
-            <UserInfoText
-              type="body2"
-              style={[pal.link]}
-              did={view.creator}
-              prefix="@"
-              asLink
-            />
-          </View>
-        ) : undefined}
-        {view.isScene && view.myState.member ? (
-          <View style={styles.detailLine}>
-            <FontAwesomeIcon
-              icon={['far', 'circle-check']}
-              style={[pal.textLight, s.mr5]}
-            />
-            <Text type="body2" style={[s.mr2, pal.textLight]}>
-              You are a member
-            </Text>
-          </View>
-        ) : undefined}
         {view.myState.muted ? (
           <View style={[styles.detailLine, pal.btn, s.p5]}>
             <FontAwesomeIcon
@@ -354,28 +254,6 @@ export const ProfileHeader = observer(function ProfileHeader({
           </View>
         ) : undefined}
       </View>
-      {view.isScene && view.creator === store.me.did ? (
-        <View style={[styles.sceneAdminContainer, pal.border]}>
-          <TouchableOpacity
-            testID="profileHeaderInviteMembersButton"
-            onPress={onPressInviteMembers}>
-            <LinearGradient
-              colors={[gradient[1], gradient[0]]}
-              start={{x: 0, y: 0}}
-              end={{x: 1, y: 1}}
-              style={[styles.btn, styles.gradientBtn, styles.sceneAdminBtn]}>
-              <FontAwesomeIcon
-                icon="user-plus"
-                style={[s.mr5, s.white]}
-                size={15}
-              />
-              <Text type="button" style={[s.bold, s.white]}>
-                Invite Members
-              </Text>
-            </LinearGradient>
-          </TouchableOpacity>
-        </View>
-      ) : undefined}
       <TouchableOpacity
         testID="profileHeaderAviButton"
         style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}
@@ -444,15 +322,6 @@ const styles = StyleSheet.create({
     flexDirection: 'row',
     marginBottom: 8,
   },
-  typeLabelWrapper: {
-    paddingHorizontal: 4,
-    borderRadius: 4,
-    marginRight: 5,
-  },
-  typeLabel: {
-    fontSize: 15,
-    fontWeight: 'bold',
-  },
 
   metricsLine: {
     flexDirection: 'row',
@@ -468,14 +337,4 @@ const styles = StyleSheet.create({
     alignItems: 'center',
     marginBottom: 5,
   },
-
-  sceneAdminContainer: {
-    borderTopWidth: 1,
-    borderBottomWidth: 1,
-    paddingVertical: 12,
-    paddingHorizontal: 12,
-  },
-  sceneAdminBtn: {
-    paddingVertical: 8,
-  },
 })
diff --git a/src/view/com/profile/ProfileMembers.tsx b/src/view/com/profile/ProfileMembers.tsx
deleted file mode 100644
index a63de9e32..000000000
--- a/src/view/com/profile/ProfileMembers.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React, {useEffect} from 'react'
-import {observer} from 'mobx-react-lite'
-import {ActivityIndicator, FlatList, View} from 'react-native'
-import {MembersViewModel, MemberItem} from '../../../state/models/members-view'
-import {ProfileCard} from './ProfileCard'
-import {ErrorMessage} from '../util/error/ErrorMessage'
-import {useStores} from '../../../state'
-
-export const ProfileMembers = observer(function ProfileMembers({
-  name,
-}: {
-  name: string
-}) {
-  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 [view, setView] = React.useState<MembersViewModel | 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 (
-      <View testID="profileMembersActivityIndicatorView">
-        <ActivityIndicator />
-      </View>
-    )
-  }
-
-  // error
-  // =
-  if (view.hasError) {
-    return (
-      <View>
-        <ErrorMessage
-          message={view.error}
-          style={{margin: 6}}
-          onPressTryAgain={onRefresh}
-        />
-      </View>
-    )
-  }
-
-  // loaded
-  // =
-  const renderItem = ({item}: {item: MemberItem}) => (
-    <ProfileCard
-      did={item.did}
-      handle={item.handle}
-      displayName={item.displayName}
-      avatar={item.avatar}
-    />
-  )
-  return (
-    <View testID="profileMembersFlatList">
-      <FlatList
-        data={view.members}
-        keyExtractor={item => item._reactKey}
-        renderItem={renderItem}
-      />
-    </View>
-  )
-})
diff --git a/src/view/index.ts b/src/view/index.ts
index 5602784f3..8ffd5957a 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 4b5c3efca..609f8e019 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 04c368089..9e937d4db 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 0a2883e69..7d5a06acd 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/(?<name>[^/]+)/followers'),
   ],
   [ProfileFollows, 'Follows', 'users', r('/profile/(?<name>[^/]+)/follows')],
-  [ProfileMembers, 'Members', 'users', r('/profile/(?<name>[^/]+)/members')],
   [
     PostThread,
     'Post',
diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx
index 7c9fac402..dd6e07611 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 64bb4f042..454ae8ade 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 <View />
@@ -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) {
@@ -153,80 +134,11 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
           }
         } else if (uiState.feed.isEmpty) {
           items = items.concat([EMPTY_ITEM])
-          if (uiState.profile.isScene) {
-            renderItem = () => (
-              <EmptyState
-                icon="user-group"
-                message="As members upvote posts, they will trend here. Follow the scene to see its trending posts in your timeline."
-              />
-            )
-          } else {
-            renderItem = () => (
-              <EmptyState
-                icon={['far', 'message']}
-                message="No posts yet!"
-                style={{paddingVertical: 40}}
-              />
-            )
-          }
-        }
-      } else if (uiState.selectedView === Sections.Scenes) {
-        if (uiState.memberships.hasContent) {
-          items = uiState.memberships.memberships.slice()
-          renderItem = (item: any) => {
-            return (
-              <ProfileCard
-                did={item.did}
-                handle={item.handle}
-                displayName={item.displayName}
-                avatar={item.avatar}
-              />
-            )
-          }
-        } else if (uiState.memberships.isEmpty) {
-          items = items.concat([EMPTY_ITEM])
-          renderItem = () => (
-            <EmptyState
-              icon="user-group"
-              message="This user hasn't joined any scenes."
-            />
-          )
-        }
-      } 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
-              ? () => (
-                  <>
-                    <FontAwesomeIcon
-                      testID="shouldAdminButton"
-                      icon="user-xmark"
-                      style={[s.mr5]}
-                      size={14}
-                    />
-                    <Text style={[s.fw400, s.f14]}>Remove</Text>
-                  </>
-                )
-              : undefined
-            return (
-              <ProfileCard
-                did={item.did}
-                handle={item.handle}
-                displayName={item.displayName}
-                avatar={item.avatar}
-                renderButton={renderButton}
-                onPressButton={() => onPressRemoveMember(item)}
-              />
-            )
-          }
-        } else if (uiState.members.isEmpty) {
-          items = items.concat([EMPTY_ITEM])
           renderItem = () => (
             <EmptyState
-              icon="user-group"
-              message="This scene doesn't have any members."
+              icon={['far', 'message']}
+              message="No posts yet!"
+              style={{paddingVertical: 40}}
             />
           )
         }
diff --git a/src/view/screens/ProfileMembers.tsx b/src/view/screens/ProfileMembers.tsx
deleted file mode 100644
index 9d6723fe9..000000000
--- 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 (
-    <View>
-      <ViewHeader title="Members" subtitle={`of ${name}`} />
-      <ProfileMembersComponent name={name} />
-    </View>
-  )
-}
diff --git a/src/view/shell/mobile/Menu.tsx b/src/view/shell/mobile/Menu.tsx
index 6a673d25f..3a6bbbc0a 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}
           />
-        </View>
-        <View style={[styles.section, pal.border]}>
-          <Text type="h5" style={[pal.text, styles.heading]}>
-            Scenes
-          </Text>
-          {store.me.memberships
-            ? store.me.memberships.memberships.map((membership, i) => (
-                <MenuItem
-                  key={i}
-                  icon={
-                    <UserAvatar
-                      size={34}
-                      displayName={membership.displayName}
-                      handle={membership.handle}
-                      avatar={membership.avatar}
-                    />
-                  }
-                  label={membership.displayName || membership.handle}
-                  url={`/profile/${membership.handle}`}
-                />
-              ))
-            : undefined}
-        </View>
-        <View style={[styles.section, pal.border]}>
-          <MenuItem
-            icon={
-              <UserGroupIcon
-                style={pal.text as StyleProp<ViewStyle>}
-                size="30"
-              />
-            }
-            label="Create a scene"
-            onPress={onPressCreateScene}
-          />
           <MenuItem
             icon={
               <CogIcon