import React, { useEffect, useRef, useState } from 'react'; import { View, Text, Animated, Easing, TouchableWithoutFeedback, TouchableOpacity, FlatList, Linking } from 'react-native'; import { batch, useDispatch } from 'react-redux'; import { Subscription } from 'rxjs'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import * as List from '../../containers/List'; import Button from '../../containers/Button'; import { toggleServerDropdown } from '../../actions/rooms'; import { selectServerRequest, serverInitAdd } from '../../actions/server'; import { appStart } from '../../actions/app'; import I18n from '../../i18n'; import EventEmitter from '../../lib/methods/helpers/events'; import ServerItem from '../../containers/ServerItem'; import database from '../../lib/database'; import { TOKEN_KEY } from '../../lib/constants'; import { useTheme } from '../../theme'; import { localAuthenticate } from '../../lib/methods/helpers/localAuthentication'; import { showConfirmationAlert } from '../../lib/methods/helpers/info'; import log, { events, logEvent } from '../../lib/methods/helpers/log'; import { headerHeight } from '../../lib/methods/helpers/navigation'; import { goRoom } from '../../lib/methods/helpers/goRoom'; import UserPreferences from '../../lib/methods/userPreferences'; import { RootEnum, TServerModel } from '../../definitions'; import styles from './styles'; import { removeServer } from '../../lib/methods'; import { useAppSelector } from '../../lib/hooks'; const ROW_HEIGHT = 68; const ANIMATION_DURATION = 200; const MAX_ROWS = 4; const ServerDropdown = () => { const animatedValue = useRef(new Animated.Value(0)).current; const subscription = useRef(); const newServerTimeout = useRef | false>(); const isMounted = useRef(false); const [servers, setServers] = useState([]); const dispatch = useDispatch(); const closeServerDropdown = useAppSelector(state => state.rooms.closeServerDropdown); const server = useAppSelector(state => state.server.server); const isMasterDetail = useAppSelector(state => state.app.isMasterDetail); const { colors } = useTheme(); const insets = useSafeAreaInsets(); useEffect(() => { if (isMounted.current) close(); }, [closeServerDropdown]); useEffect(() => { isMounted.current = true; const init = async () => { const serversDB = database.servers; const observable = await serversDB.get('servers').query().observeWithColumns(['name']); subscription.current = observable.subscribe(data => { setServers(data); }); Animated.timing(animatedValue, { toValue: 1, duration: ANIMATION_DURATION, easing: Easing.inOut(Easing.quad), useNativeDriver: true }).start(); }; init(); return () => { if (newServerTimeout.current) { clearTimeout(newServerTimeout.current); newServerTimeout.current = false; } if (subscription.current && subscription.current.unsubscribe) { subscription.current.unsubscribe(); } }; }, []); const close = () => { Animated.timing(animatedValue, { toValue: 0, duration: ANIMATION_DURATION, easing: Easing.inOut(Easing.quad), useNativeDriver: true }).start(() => dispatch(toggleServerDropdown())); }; const createWorkspace = async () => { logEvent(events.RL_CREATE_NEW_WORKSPACE); try { await Linking.openURL('https://cloud.rocket.chat/trial'); } catch (e) { log(e); } }; const navToNewServer = (previousServer: string) => { batch(() => { dispatch(appStart({ root: RootEnum.ROOT_OUTSIDE })); dispatch(serverInitAdd(previousServer)); }); }; const addServer = () => { logEvent(events.RL_ADD_SERVER); close(); setTimeout(() => { navToNewServer(server); }, ANIMATION_DURATION); }; const select = async (serverParam: string, version?: string) => { close(); if (server !== serverParam) { logEvent(events.RL_CHANGE_SERVER); const userId = UserPreferences.getString(`${TOKEN_KEY}-${serverParam}`); if (isMasterDetail) { goRoom({ item: {}, isMasterDetail }); } if (!userId) { setTimeout(() => { navToNewServer(server); newServerTimeout.current = setTimeout(() => { EventEmitter.emit('NewServer', { server: serverParam }); }, ANIMATION_DURATION); }, ANIMATION_DURATION); } else { await localAuthenticate(serverParam); dispatch(selectServerRequest(serverParam, version, true, true)); } } }; const remove = (server: string) => showConfirmationAlert({ message: I18n.t('This_will_remove_all_data_from_this_server'), confirmationText: I18n.t('Delete'), onPress: async () => { close(); try { await removeServer({ server }); } catch { // do nothing } } }); const renderItem = ({ item }: { item: { id: string; iconURL: string; name: string; version: string } }) => ( select(item.id, item.version)} onLongPress={() => item.id === server || remove(item.id)} hasCheck={item.id === server} /> ); const initialTop = 87 + Math.min(servers.length, MAX_ROWS) * ROW_HEIGHT; const statusBarHeight = insets?.top ?? 0; const heightDestination = isMasterDetail ? headerHeight + statusBarHeight : 0; const translateY = animatedValue.interpolate({ inputRange: [0, 1], outputRange: [-initialTop, heightDestination] }); const backdropOpacity = animatedValue.interpolate({ inputRange: [0, 1], outputRange: [0, colors.backdropOpacity] }); return ( <> {I18n.t('Server')} {I18n.t('Add_Server')} item.id} renderItem={renderItem} ItemSeparatorComponent={List.Separator} keyboardShouldPersistTaps='always' />