about summary refs log tree commit diff
path: root/src/view/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com')
-rw-r--r--src/view/com/profile/ProfileCard.tsx59
-rw-r--r--src/view/com/profile/ProfileHeader.tsx9
-rw-r--r--src/view/com/profile/ProfileMembers.tsx69
-rw-r--r--src/view/com/util/Selector.tsx2
4 files changed, 135 insertions, 4 deletions
diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx
new file mode 100644
index 000000000..cb58aec3f
--- /dev/null
+++ b/src/view/com/profile/ProfileCard.tsx
@@ -0,0 +1,59 @@
+import React from 'react'
+import {StyleSheet, Text, View} from 'react-native'
+import {Link} from '../util/Link'
+import {UserAvatar} from '../util/UserAvatar'
+import {s, colors} from '../../lib/styles'
+
+export function ProfileCard({
+  did,
+  handle,
+  displayName,
+  description,
+}: {
+  did: string
+  handle: string
+  displayName?: string
+  description?: string
+}) {
+  return (
+    <Link style={styles.outer} href={`/profile/${handle}`} title={handle}>
+      <View style={styles.layout}>
+        <View style={styles.layoutAvi}>
+          <UserAvatar size={40} displayName={displayName} handle={handle} />
+        </View>
+        <View style={styles.layoutContent}>
+          <Text style={[s.f16, s.bold]}>{displayName || handle}</Text>
+          <Text style={[s.f15, s.gray5]}>@{handle}</Text>
+        </View>
+      </View>
+    </Link>
+  )
+}
+
+const styles = StyleSheet.create({
+  outer: {
+    marginTop: 1,
+    backgroundColor: colors.white,
+  },
+  layout: {
+    flexDirection: 'row',
+  },
+  layoutAvi: {
+    width: 60,
+    paddingLeft: 10,
+    paddingTop: 10,
+    paddingBottom: 10,
+  },
+  avi: {
+    width: 40,
+    height: 40,
+    borderRadius: 20,
+    resizeMode: 'cover',
+  },
+  layoutContent: {
+    flex: 1,
+    paddingRight: 10,
+    paddingTop: 12,
+    paddingBottom: 10,
+  },
+})
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index 984190283..d1dcd0525 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -57,6 +57,9 @@ export const ProfileHeader = observer(function ProfileHeader({
   const onPressFollows = () => {
     store.nav.navigate(`/profile/${view.handle}/follows`)
   }
+  const onPressMembers = () => {
+    store.nav.navigate(`/profile/${view.handle}/members`)
+  }
 
   // loading
   // =
@@ -173,12 +176,12 @@ export const ProfileHeader = observer(function ProfileHeader({
           {view.isScene ? (
             <TouchableOpacity
               style={[s.flexRow, s.mr10]}
-              onPress={onPressFollows}>
+              onPress={onPressMembers}>
               <Text style={[s.bold, s.mr2, styles.metricsText]}>
-                {view.followsCount}
+                {view.membersCount}
               </Text>
               <Text style={[s.gray5, styles.metricsText]}>
-                {pluralize(view.followsCount, 'member')}
+                {pluralize(view.membersCount, 'member')}
               </Text>
             </TouchableOpacity>
           ) : undefined}
diff --git a/src/view/com/profile/ProfileMembers.tsx b/src/view/com/profile/ProfileMembers.tsx
new file mode 100644
index 000000000..11db02054
--- /dev/null
+++ b/src/view/com/profile/ProfileMembers.tsx
@@ -0,0 +1,69 @@
+import React, {useState, useEffect} from 'react'
+import {observer} from 'mobx-react-lite'
+import {ActivityIndicator, FlatList, Text, View} from 'react-native'
+import {MembersViewModel, MemberItem} from '../../../state/models/members-view'
+import {ProfileCard} from './ProfileCard'
+import {useStores} from '../../../state'
+
+export const ProfileMembers = observer(function ProfileMembers({
+  name,
+}: {
+  name: string
+}) {
+  const store = useStores()
+  const [view, setView] = useState<MembersViewModel | undefined>()
+
+  useEffect(() => {
+    if (view?.params.actor === name) {
+      console.log('Members doing nothing')
+      return // no change needed? or trigger refresh?
+    }
+    console.log('Fetching members', name)
+    const newView = new MembersViewModel(store, {actor: name})
+    setView(newView)
+    newView.setup().catch(err => console.error('Failed to fetch members', err))
+  }, [name, view?.params.actor, store])
+
+  // loading
+  // =
+  if (
+    !view ||
+    (view.isLoading && !view.isRefreshing) ||
+    view.params.actor !== name
+  ) {
+    return (
+      <View>
+        <ActivityIndicator />
+      </View>
+    )
+  }
+
+  // error
+  // =
+  if (view.hasError) {
+    return (
+      <View>
+        <Text>{view.error}</Text>
+      </View>
+    )
+  }
+
+  // loaded
+  // =
+  const renderItem = ({item}: {item: MemberItem}) => (
+    <ProfileCard
+      did={item.did}
+      handle={item.handle}
+      displayName={item.displayName}
+    />
+  )
+  return (
+    <View>
+      <FlatList
+        data={view.members}
+        keyExtractor={item => item._reactKey}
+        renderItem={renderItem}
+      />
+    </View>
+  )
+})
diff --git a/src/view/com/util/Selector.tsx b/src/view/com/util/Selector.tsx
index e68310682..06e8cda80 100644
--- a/src/view/com/util/Selector.tsx
+++ b/src/view/com/util/Selector.tsx
@@ -41,7 +41,7 @@ export function Selector({
       width: middle.width,
     }
     return [left, middle, right]
-  }, [selectedIndex, itemLayouts])
+  }, [selectedIndex, items, itemLayouts])
 
   const interp = swipeGestureInterp || DEFAULT_SWIPE_GESTURE_INTERP
   const underlinePos = useAnimatedStyle(() => {