// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, {useCallback, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; import {View} from 'react-native'; import {addCurrentUserToTeam, fetchTeamsForComponent, handleTeamChange} from '@actions/remote/team'; import FormattedText from '@components/formatted_text'; import Empty from '@components/illustrations/no_team'; import Loading from '@components/loading'; import TeamList from '@components/team_list'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import useDidMount from '@hooks/did_mount'; import useNavButtonPressed from '@hooks/navigation_button_pressed'; import SecurityManager from '@managers/security_manager'; import {dismissModal} from '@screens/navigation'; import {logDebug} from '@utils/log'; import {alertTeamAddError} from '@utils/navigation'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; import type {AvailableScreens} from '@typings/screens/navigation'; type Props = { joinedIds: Set; componentId: AvailableScreens; closeButtonId: string; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ container: { paddingHorizontal: 10, paddingVertical: 5, flex: 1, }, empty: { flex: 1, alignItems: 'center', justifyContent: 'center', }, loading: { flex: 1, alignItems: 'center', justifyContent: 'center', }, title: { color: theme.centerChannelColor, marginTop: 16, ...typography('Heading', 400, 'Regular'), }, description: { color: theme.centerChannelColor, marginTop: 8, maxWidth: 334, ...typography('Body', 200, 'Regular'), }, })); export default function JoinTeam({ joinedIds, componentId, closeButtonId, }: Props) { const serverUrl = useServerUrl(); const theme = useTheme(); const styles = getStyleSheet(theme); const intl = useIntl(); const page = useRef(0); const hasMore = useRef(true); const mounted = useRef(true); const [loading, setLoading] = useState(true); const [joining, setJoining] = useState(false); const [otherTeams, setOtherTeams] = useState([]); const loadTeams = useCallback(async () => { setLoading(true); const resp = await fetchTeamsForComponent(serverUrl, page.current, joinedIds); page.current = resp.page; hasMore.current = resp.hasMore; if (resp.teams.length && mounted.current) { const teams = resp.teams.filter((t) => t.delete_at === 0); setOtherTeams((cur) => [...cur, ...teams]); } setLoading(false); }, [joinedIds, serverUrl]); const onEndReached = useCallback(() => { if (hasMore.current && !loading) { loadTeams(); } }, [loadTeams, loading]); const onPress = useCallback(async (teamId: string) => { setJoining(true); const {error} = await addCurrentUserToTeam(serverUrl, teamId); if (error) { alertTeamAddError(error, intl); logDebug('error joining a team:', error); setJoining(false); } else { handleTeamChange(serverUrl, teamId); dismissModal({componentId}); } }, [serverUrl, componentId, intl]); useDidMount(() => { loadTeams(); return () => { mounted.current = false; }; }); const onClosePressed = useCallback(() => { return dismissModal({componentId}); }, [componentId]); useNavButtonPressed(closeButtonId, componentId, onClosePressed, []); useAndroidHardwareBackHandler(componentId, onClosePressed); const hasOtherTeams = Boolean(otherTeams.length); let body; if ((loading && !hasOtherTeams) || joining) { body = (); } else if (hasOtherTeams) { body = ( ); } else { body = ( ); } return ( {body} ); }