From 6432667f608fae447b59e41b9f8bb64b564205a1 Mon Sep 17 00:00:00 2001
From: Samuel Newman <mozzius@protonmail.com>
Date: Tue, 9 Sep 2025 20:20:33 +0300
Subject: ALF lists screen (#8941)

* alf list screens

* relocate to `#/screens`, balkanize

* use useBreakpoints

* showCancel on subscribe menu

* fix typo
---
 src/screens/ProfileList/AboutSection.tsx | 136 +++++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)
 create mode 100644 src/screens/ProfileList/AboutSection.tsx

(limited to 'src/screens/ProfileList/AboutSection.tsx')

diff --git a/src/screens/ProfileList/AboutSection.tsx b/src/screens/ProfileList/AboutSection.tsx
new file mode 100644
index 000000000..47f29b838
--- /dev/null
+++ b/src/screens/ProfileList/AboutSection.tsx
@@ -0,0 +1,136 @@
+import {useCallback, useImperativeHandle, useState} from 'react'
+import {View} from 'react-native'
+import {type AppBskyGraphDefs} from '@atproto/api'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {isNative} from '#/platform/detection'
+import {useSession} from '#/state/session'
+import {ListMembers} from '#/view/com/lists/ListMembers'
+import {EmptyState} from '#/view/com/util/EmptyState'
+import {type ListRef} from '#/view/com/util/List'
+import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn'
+import {atoms as a, useBreakpoints} from '#/alf'
+import {Button, ButtonIcon, ButtonText} from '#/components/Button'
+import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person'
+
+interface SectionRef {
+  scrollToTop: () => void
+}
+
+interface AboutSectionProps {
+  ref?: React.Ref<SectionRef>
+  list: AppBskyGraphDefs.ListView
+  onPressAddUser: () => void
+  headerHeight: number
+  scrollElRef: ListRef
+}
+
+export function AboutSection({
+  ref,
+  list,
+  onPressAddUser,
+  headerHeight,
+  scrollElRef,
+}: AboutSectionProps) {
+  const {_} = useLingui()
+  const {currentAccount} = useSession()
+  const {gtMobile} = useBreakpoints()
+  const [isScrolledDown, setIsScrolledDown] = useState(false)
+  const isOwner = list.creator.did === currentAccount?.did
+
+  const onScrollToTop = useCallback(() => {
+    scrollElRef.current?.scrollToOffset({
+      animated: isNative,
+      offset: -headerHeight,
+    })
+  }, [scrollElRef, headerHeight])
+
+  useImperativeHandle(ref, () => ({
+    scrollToTop: onScrollToTop,
+  }))
+
+  const renderHeader = useCallback(() => {
+    if (!isOwner) {
+      return <View />
+    }
+    if (!gtMobile) {
+      return (
+        <View style={[a.px_sm, a.py_sm]}>
+          <Button
+            testID="addUserBtn"
+            label={_(msg`Add a user to this list`)}
+            onPress={onPressAddUser}
+            color="primary"
+            size="small"
+            variant="outline"
+            style={[a.py_md]}>
+            <ButtonIcon icon={PersonPlusIcon} />
+            <ButtonText>
+              <Trans>Add people</Trans>
+            </ButtonText>
+          </Button>
+        </View>
+      )
+    }
+    return (
+      <View style={[a.px_lg, a.py_md, a.flex_row_reverse]}>
+        <Button
+          testID="addUserBtn"
+          label={_(msg`Add a user to this list`)}
+          onPress={onPressAddUser}
+          color="primary"
+          size="small"
+          variant="ghost"
+          style={[a.py_sm]}>
+          <ButtonIcon icon={PersonPlusIcon} />
+          <ButtonText>
+            <Trans>Add people</Trans>
+          </ButtonText>
+        </Button>
+      </View>
+    )
+  }, [isOwner, _, onPressAddUser, gtMobile])
+
+  const renderEmptyState = useCallback(() => {
+    return (
+      <View style={[a.gap_xl, a.align_center]}>
+        <EmptyState icon="users-slash" message={_(msg`This list is empty.`)} />
+        {isOwner && (
+          <Button
+            testID="emptyStateAddUserBtn"
+            label={_(msg`Start adding people`)}
+            onPress={onPressAddUser}
+            color="primary"
+            size="small">
+            <ButtonIcon icon={PersonPlusIcon} />
+            <ButtonText>
+              <Trans>Start adding people!</Trans>
+            </ButtonText>
+          </Button>
+        )}
+      </View>
+    )
+  }, [_, onPressAddUser, isOwner])
+
+  return (
+    <View>
+      <ListMembers
+        testID="listItems"
+        list={list.uri}
+        scrollElRef={scrollElRef}
+        renderHeader={renderHeader}
+        renderEmptyState={renderEmptyState}
+        headerOffset={headerHeight}
+        onScrolledDownChange={setIsScrolledDown}
+      />
+      {isScrolledDown && (
+        <LoadLatestBtn
+          onPress={onScrollToTop}
+          label={_(msg`Scroll to top`)}
+          showIndicator={false}
+        />
+      )}
+    </View>
+  )
+}
-- 
cgit 1.4.1

