Bluesky app fork with some witchin' additions 馃挮
at main 138 lines 4.0 kB view raw
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}