1- import React , { useEffect , useRef , useState } from 'react'
2- import { KeyboardAvoidingView , TextInput , View } from 'react-native'
1+ import React , { useCallback , useEffect , useState } from 'react'
2+ import { KeyboardAvoidingView , Platform , View } from 'react-native'
33
44import { defaultPalette } from '../../styles/palettes/default.palette'
55import { Appbar } from '../Appbar/Appbar.component'
66import { Button } from '../Button/Button.component'
77import { ChannelMembershipProps } from './ChannelMembership.types'
88import { createLogger } from '../../utils/logger'
99import { ChannelMembershipAppbarHeaderTitle } from './ChannelMembershipAppbarHeaderTitle.component'
10- import { SelectableListOption } from './ChannelMembershipList/ChannelMembershipList.types'
11- import { ChannelMembershipList } from './ChannelMembershipList/ChannelMembershipList.component'
12- import { Typography } from '../Typography/Typography.component'
10+ import { ChannelMembershipList } from './ChannelMembershipList.component'
1311import { defaultTheme } from '../../styles/themes/default.theme'
14- import { Input } from '../Input/Input.component'
15- import Fuse from 'fuse.js'
12+ import { useDispatch , useSelector } from 'react-redux'
13+ import { navigationActions } from '../../store/navigation/navigation.slice'
14+ import { ScreenNames } from '../../const/ScreenNames.enum'
15+ import { communities } from '@quiet/state-manager'
1616
1717const logger = createLogger ( 'ChannelMembership' )
1818
19+ const TITLE = 'Permissions'
20+ const NON_OWNER_TITLE = 'Members'
21+
1922export const ChannelMembership : React . FC < ChannelMembershipProps > = ( {
2023 channelName,
2124 channelId,
22- userProfiles = { } ,
2325 community,
24- updateChannelMembership,
26+ members,
27+ memberCount,
2528 handleBackButton,
2629} ) => {
30+ const dispatch = useDispatch ( )
2731 const [ displayedName , setDisplayedName ] = useState < string > ( '' )
2832 const [ loading , setLoading ] = useState < boolean > ( false )
29- const [ options , setOptions ] = useState < SelectableListOption [ ] > ( [ ] )
30- const [ visibleOptionIndices , setVisibleOptionIndices ] = useState < Set < number > > ( new Set ( ) )
31- const [ inputError , setInputError ] = useState < string | undefined > ( )
32- const [ membershipSearchInput , setMembershipSearchInput ] = useState < string | undefined > ( )
33- const [ fuzzySearch , setFuzzySearch ] = useState < Fuse < SelectableListOption > | undefined > ( )
34- const inputRef = useRef < TextInput > ( null )
33+ const [ headerTitle , setHeaderTitle ] = useState < string > ( '' )
3534
36- const _initializeOptions = ( ) => {
37- const initialOptions : SelectableListOption [ ] = [ ]
38- const visibleIndices : Set < number > = new Set ( )
39- let index = 0
40- for ( const user of Object . values ( userProfiles ) ) {
41- let mutable = true
42- let selected = false
43- if ( ( user . channels ?? [ ] ) . includes ( channelId ) ) {
44- mutable = false
45- selected = true
46- }
47- initialOptions . push ( { label : user . nickname , id : user . userId , selected, index, mutable, hide : false } )
48- visibleIndices . add ( index )
49- index ++
50- }
51- setOptions ( initialOptions )
52- setVisibleOptionIndices ( visibleIndices )
53- setFuzzySearch (
54- new Fuse ( initialOptions , {
55- keys : [ 'label' ] ,
56- minMatchCharLength : 1 ,
57- ignoreDiacritics : true ,
58- threshold : 0.3 ,
59- } )
60- )
61- }
35+ const isOwner = useSelector ( communities . selectors . isOwner )
6236
63- const onPress = ( ) => {
37+ const onPress = useCallback ( ( ) => {
6438 setLoading ( true )
65- updateChannelMembership ( options . filter ( option => option . selected && option . mutable ) . map ( option => option . id ) )
66- setOptions ( [ ] )
67- setVisibleOptionIndices ( new Set ( ) )
68- }
39+ dispatch (
40+ navigationActions . replaceScreen ( {
41+ screen : ScreenNames . UpdateChannelMembershipScreen ,
42+ params : {
43+ channelName,
44+ channelId,
45+ } ,
46+ } )
47+ )
48+ } , [ dispatch , channelName , channelId ] )
6949
7050 const goBack = ( ) => {
7151 if ( ! loading ) {
72- setOptions ( [ ] )
7352 handleBackButton ( )
7453 }
7554 }
@@ -78,82 +57,67 @@ export const ChannelMembership: React.FC<ChannelMembershipProps> = ({
7857 useEffect ( ( ) => {
7958 if ( channelName !== '' ) {
8059 setDisplayedName ( channelName )
81- _initializeOptions ( )
8260 }
8361 } , [ channelName ] )
8462
85- const _setAllOptionsVisible = ( ) => {
86- return new Set ( Array ( options . length ) . keys ( ) )
87- }
88-
89- const _fuzzyFilterUsers = ( filterText : string ) : Set < number > => {
90- if ( fuzzySearch == null ) {
91- return _setAllOptionsVisible ( )
92- }
93- const searchResults = fuzzySearch . search ( filterText )
94- return new Set ( searchResults . map ( result => result . item . index ) )
95- }
96-
97- const onChangeText = ( value : string ) => {
98- setInputError ( undefined )
99- setMembershipSearchInput ( value )
100- if ( value === '' ) {
101- setVisibleOptionIndices ( _setAllOptionsVisible ( ) )
102- return
103- }
104- const foundIndices = _fuzzyFilterUsers ( value )
105- setVisibleOptionIndices ( foundIndices )
106- }
63+ useEffect ( ( ) => {
64+ setHeaderTitle ( isOwner ? TITLE : NON_OWNER_TITLE )
65+ } , [ isOwner ] )
10766
10867 return (
109- < View style = { { flex : 1 , backgroundColor : defaultPalette . background . white } } testID = { 'channel-membership-component' } >
68+ < View
69+ style = { { flex : 1 , backgroundColor : defaultPalette . background . white } }
70+ testID = { `channel-membership-component-${ channelId } ` }
71+ >
11072 < KeyboardAvoidingView
111- behavior = ' height'
73+ behavior = { Platform . select ( { ios : 'padding' , android : ' height' } ) }
11274 style = { {
11375 flex : 1 ,
114- marginTop : 24 ,
115- paddingLeft : 20 ,
116- paddingRight : 20 ,
11776 marginBottom : 16 ,
11877 } }
11978 >
12079 < Appbar
121- title = { 'Add members' }
122- titleComponent = { < ChannelMembershipAppbarHeaderTitle title = { 'Add members' } channelName = { displayedName } /> }
80+ title = { headerTitle }
81+ titleComponent = {
82+ < ChannelMembershipAppbarHeaderTitle
83+ title = { headerTitle }
84+ channelName = { displayedName }
85+ membershipCount = { memberCount }
86+ />
87+ }
12388 back = { goBack }
12489 />
12590 < View
12691 style = { {
127- padding : 24 ,
92+ paddingTop : 16 ,
93+ display : 'flex' ,
94+ flexDirection : 'column' ,
95+ gap : 32 ,
12896 } }
12997 >
130- < Input
131- onChangeText = { onChangeText }
132- subtitle = { `Add members with '@'` }
133- placeholder = { 'E.g. @jane123' }
134- value = { membershipSearchInput }
135- length = { 20 }
136- disabled = { loading }
137- validation = { inputError }
138- ref = { inputRef }
139- autoCorrect = { false }
140- />
141- < Typography fontSize = { 10 } style = { { paddingTop : 18 , color : defaultTheme . palette . typography . gray50 } } >
142- MEMBERS
143- </ Typography >
144- < ChannelMembershipList
145- options = { options }
146- visibleOptionsIndices = { visibleOptionIndices }
147- setOptions = { setOptions }
148- channelId = { channelId }
149- userProfiles = { userProfiles }
150- />
151- < View style = { { paddingTop : 16 + 12 } } >
152- < Button title = { 'Update Channel Membership' } onPress = { onPress } loading = { loading } />
153- </ View >
154- < View style = { { paddingTop : 24 } } >
155- < Button title = { 'Never mind' } onPress = { goBack } negative />
156- </ View >
98+ { isOwner && (
99+ < View >
100+ < View
101+ style = { {
102+ width : 'auto' ,
103+ display : 'flex' ,
104+ flexDirection : 'row' ,
105+ alignItems : 'flex-end' ,
106+ alignSelf : 'flex-end' ,
107+ paddingHorizontal : 16 ,
108+ paddingBottom : 16 ,
109+ } }
110+ >
111+ < Button
112+ title = { 'Add members' }
113+ onPress = { onPress }
114+ testID = { `channel-membership-component-add-members-${ channelId } ` }
115+ />
116+ </ View >
117+ < View style = { { height : 1 , backgroundColor : defaultTheme . palette . background . gray06 } } />
118+ </ View >
119+ ) }
120+ < ChannelMembershipList members = { members } channelId = { channelId } />
157121 </ View >
158122 </ KeyboardAvoidingView >
159123 </ View >
0 commit comments