import React, { useEffect, useLayoutEffect, useState } from 'react'; import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'; import { FlatList } from 'react-native'; import { Q } from '@nozbe/watermelondb'; import * as List from '../../containers/List'; import database from '../../lib/database'; import I18n from '../../i18n'; import log, { events, logEvent } from '../../lib/methods/helpers/log'; import SearchBox from '../../containers/SearchBox'; import * as HeaderButton from '../../containers/HeaderButton'; import StatusBar from '../../containers/StatusBar'; import { useTheme } from '../../theme'; import SafeAreaView from '../../containers/SafeAreaView'; import { sendLoadingEvent } from '../../containers/Loading'; import { animateNextTransition } from '../../lib/methods/helpers/layoutAnimation'; import { showErrorAlert } from '../../lib/methods/helpers/info'; import { ChatsStackParamList } from '../../stacks/types'; import { TSubscriptionModel, SubscriptionType } from '../../definitions'; import { getRoomTitle, hasPermission, useDebounce } from '../../lib/methods/helpers'; import { Services } from '../../lib/services'; import { useAppSelector } from '../../lib/hooks'; type TNavigation = StackNavigationProp; type TRoute = RouteProp; const QUERY_SIZE = 50; const AddExistingChannelView = () => { const [channels, setChannels] = useState([]); const [selected, setSelected] = useState([]); const { colors } = useTheme(); const navigation = useNavigation(); const { params: { teamId } } = useRoute(); const { addTeamChannelPermission, isMasterDetail } = useAppSelector(state => ({ isMasterDetail: state.app.isMasterDetail, addTeamChannelPermission: state.permissions['add-team-channel'] })); useLayoutEffect(() => { setHeader(); }, [selected.length]); useEffect(() => { query(); }, []); const setHeader = () => { const options: StackNavigationOptions = { headerTitle: I18n.t('Add_Existing_Channel') }; if (isMasterDetail) { options.headerLeft = () => ; } options.headerRight = () => selected.length > 0 && ( ); navigation.setOptions(options); }; const query = async (stringToSearch = '') => { try { const db = database.active; const channels = await db .get('subscriptions') .query( Q.where('team_id', ''), Q.where('t', Q.oneOf(['c', 'p'])), Q.where('name', Q.like(`%${stringToSearch}%`)), Q.experimentalTake(QUERY_SIZE), Q.experimentalSortBy('room_updated_at', Q.desc) ) .fetch(); const asyncFilter = async (channelsArray: TSubscriptionModel[]) => { const results = await Promise.all( channelsArray.map(async channel => { if (channel.prid) { return false; } const permissions = await hasPermission([addTeamChannelPermission], channel.rid); if (!permissions[0]) { return false; } return true; }) ); return channelsArray.filter((_v: any, index: number) => results[index]); }; const channelFiltered = await asyncFilter(channels); setChannels(channelFiltered); } catch (e) { log(e); } }; const onSearchChangeText = useDebounce((text: string) => { query(text); }, 300); const isChecked = (rid: string) => selected.includes(rid); const toggleChannel = (rid: string) => { animateNextTransition(); if (!isChecked(rid)) { logEvent(events.AEC_ADD_CHANNEL); setSelected([...selected, rid]); } else { logEvent(events.AEC_REMOVE_CHANNEL); const filterSelected = selected.filter(el => el !== rid); setSelected(filterSelected); } }; const submit = async () => { sendLoadingEvent({ visible: true }); try { logEvent(events.CT_ADD_ROOM_TO_TEAM); const result = await Services.addRoomsToTeam({ rooms: selected, teamId }); if (result.success) { sendLoadingEvent({ visible: false }); // Expect that after you add an existing channel to a team, the user should move back to the team navigation.navigate('RoomView'); } } catch (e: any) { logEvent(events.CT_ADD_ROOM_TO_TEAM_F); showErrorAlert(I18n.t(e.data.error), I18n.t('Add_Existing_Channel'), () => {}); sendLoadingEvent({ visible: false }); } }; return ( item.id} ListHeaderComponent={ onSearchChangeText(text)} testID='add-existing-channel-view-search' /> } renderItem={({ item }: { item: TSubscriptionModel }) => { // TODO: reuse logic inside RoomTypeIcon const icon = item.t === SubscriptionType.GROUP && !item?.teamId ? 'channel-private' : 'channel-public'; return ( toggleChannel(item.rid)} testID={`add-existing-channel-view-item-${item.name}`} left={() => } right={() => (isChecked(item.rid) ? : null)} /> ); }} ItemSeparatorComponent={List.Separator} contentContainerStyle={{ backgroundColor: colors.backgroundColor }} keyboardShouldPersistTaps='always' /> ); }; export default AddExistingChannelView;