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