forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {useCallback, useImperativeHandle, useState} from 'react'
2import {View} from 'react-native'
3import {type AppBskyGraphDefs} from '@atproto/api'
4import {msg, Trans} from '@lingui/macro'
5import {useLingui} from '@lingui/react'
6
7import {useSession} from '#/state/session'
8import {ListMembers} from '#/view/com/lists/ListMembers'
9import {EmptyState} from '#/view/com/util/EmptyState'
10import {type ListRef} from '#/view/com/util/List'
11import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn'
12import {atoms as a, useBreakpoints} from '#/alf'
13import {Button, ButtonIcon, ButtonText} from '#/components/Button'
14import {BulletList_Stroke1_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList'
15import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person'
16import {IS_NATIVE} from '#/env'
17
18interface SectionRef {
19 scrollToTop: () => void
20}
21
22interface AboutSectionProps {
23 ref?: React.Ref<SectionRef>
24 list: AppBskyGraphDefs.ListView
25 onPressAddUser: () => void
26 headerHeight: number
27 scrollElRef: ListRef
28}
29
30export function AboutSection({
31 ref,
32 list,
33 onPressAddUser,
34 headerHeight,
35 scrollElRef,
36}: AboutSectionProps) {
37 const {_} = useLingui()
38 const {currentAccount} = useSession()
39 const {gtMobile} = useBreakpoints()
40 const [isScrolledDown, setIsScrolledDown] = useState(false)
41 const isOwner = list.creator.did === currentAccount?.did
42
43 const onScrollToTop = useCallback(() => {
44 scrollElRef.current?.scrollToOffset({
45 animated: IS_NATIVE,
46 offset: -headerHeight,
47 })
48 }, [scrollElRef, headerHeight])
49
50 useImperativeHandle(ref, () => ({
51 scrollToTop: onScrollToTop,
52 }))
53
54 const renderHeader = useCallback(() => {
55 if (!isOwner) {
56 return <View />
57 }
58 if (!gtMobile) {
59 return (
60 <View style={[a.px_sm, a.py_sm]}>
61 <Button
62 testID="addUserBtn"
63 label={_(msg`Add a user to this list`)}
64 onPress={onPressAddUser}
65 color="primary"
66 size="small"
67 variant="outline"
68 style={[a.py_md]}>
69 <ButtonIcon icon={PersonPlusIcon} />
70 <ButtonText>
71 <Trans>Add people</Trans>
72 </ButtonText>
73 </Button>
74 </View>
75 )
76 }
77 return (
78 <View style={[a.px_lg, a.py_md, a.flex_row_reverse]}>
79 <Button
80 testID="addUserBtn"
81 label={_(msg`Add a user to this list`)}
82 onPress={onPressAddUser}
83 color="primary"
84 size="small"
85 variant="ghost"
86 style={[a.py_sm]}>
87 <ButtonIcon icon={PersonPlusIcon} />
88 <ButtonText>
89 <Trans>Add people</Trans>
90 </ButtonText>
91 </Button>
92 </View>
93 )
94 }, [isOwner, _, onPressAddUser, gtMobile])
95
96 const renderEmptyState = useCallback(() => {
97 return (
98 <View style={[a.gap_xl, a.align_center]}>
99 <EmptyState icon={ListIcon} message={_(msg`This list is empty.`)} />
100 {isOwner && (
101 <Button
102 testID="emptyStateAddUserBtn"
103 label={_(msg`Start adding people`)}
104 onPress={onPressAddUser}
105 color="primary"
106 size="small">
107 <ButtonIcon icon={PersonPlusIcon} />
108 <ButtonText>
109 <Trans>Start adding people!</Trans>
110 </ButtonText>
111 </Button>
112 )}
113 </View>
114 )
115 }, [_, isOwner, onPressAddUser])
116
117 return (
118 <View>
119 <ListMembers
120 testID="listItems"
121 list={list.uri}
122 scrollElRef={scrollElRef}
123 renderHeader={renderHeader}
124 renderEmptyState={renderEmptyState}
125 headerOffset={headerHeight}
126 onScrolledDownChange={setIsScrolledDown}
127 />
128 {isScrolledDown && (
129 <LoadLatestBtn
130 onPress={onScrollToTop}
131 label={_(msg`Scroll to top`)}
132 showIndicator={false}
133 />
134 )}
135 </View>
136 )
137}