forked from Ivasoft/mattermost-mobile
Compare commits
39 Commits
migrate-to
...
modularize
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ade9cb49d9 | ||
|
|
3643adf391 | ||
|
|
778b512951 | ||
|
|
4d827d1e44 | ||
|
|
92d37995c5 | ||
|
|
b86ec123c0 | ||
|
|
6e5c443c26 | ||
|
|
b22c80f244 | ||
|
|
ed15730d53 | ||
|
|
fc55dcd808 | ||
|
|
46bdc8fb26 | ||
|
|
5b71c88e89 | ||
|
|
0adc4a1eed | ||
|
|
dfa015aca8 | ||
|
|
eaf783ad72 | ||
|
|
eb76543229 | ||
|
|
5d0fb1444c | ||
|
|
fd21cbc2f1 | ||
|
|
95985b1940 | ||
|
|
ff7d3c9580 | ||
|
|
f1e5e6f58b | ||
|
|
c4d557f0f0 | ||
|
|
1d5fae16c5 | ||
|
|
afa446da59 | ||
|
|
0f0880bffc | ||
|
|
fdeac9001d | ||
|
|
ef2537be07 | ||
|
|
1ecfac0823 | ||
|
|
5fdb1f05da | ||
|
|
2acbc13a6d | ||
|
|
68da5abfc1 | ||
|
|
09c40aaa74 | ||
|
|
1328902814 | ||
|
|
391bd85d9d | ||
|
|
c212f014ec | ||
|
|
1fbd1f43fe | ||
|
|
9ce8144a50 | ||
|
|
fae02306c8 | ||
|
|
461f49cf6c |
@@ -59,7 +59,7 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
||||
};
|
||||
});
|
||||
|
||||
export default function SelectedUsers({
|
||||
export default function SelectedUsersPanel({
|
||||
selectedIds,
|
||||
teammateNameDisplay,
|
||||
warnCount,
|
||||
14
app/components/users_modal/index.tsx
Normal file
14
app/components/users_modal/index.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
|
||||
import {observeProfileLongPresTutorial} from '@queries/app/global';
|
||||
|
||||
import UsersModal from './users_modal';
|
||||
|
||||
const enhanced = withObservables([], () => ({
|
||||
tutorialWatched: observeProfileLongPresTutorial(),
|
||||
}));
|
||||
|
||||
export default enhanced(UsersModal);
|
||||
234
app/components/users_modal/users_modal.tsx
Normal file
234
app/components/users_modal/users_modal.tsx
Normal file
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {MutableRefObject, useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react';
|
||||
import {MessageDescriptor, useIntl} from 'react-intl';
|
||||
import {Keyboard, Platform, StyleSheet, View} from 'react-native';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import Loading from '@components/loading';
|
||||
import SelectedUsersPanel from '@components/selected_users_panel';
|
||||
import UserList from '@components/user_list';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {debounce} from '@helpers/api/general';
|
||||
import useNavButtonPressed from '@hooks/navigation_button_pressed';
|
||||
import {dismissModal, setButtons} from '@screens/navigation';
|
||||
import {filterProfilesMatchingTerm} from '@utils/user';
|
||||
|
||||
const style = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
searchBar: {
|
||||
marginLeft: 12,
|
||||
marginRight: Platform.select({ios: 4, default: 12}),
|
||||
marginVertical: 12,
|
||||
},
|
||||
});
|
||||
|
||||
const ACTION_BUTTON = 'action-button';
|
||||
const CLOSE_BUTTON = 'close-dms';
|
||||
|
||||
const close = () => {
|
||||
Keyboard.dismiss();
|
||||
dismissModal();
|
||||
};
|
||||
|
||||
type getProfilesError = {
|
||||
users?: undefined;
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
type getProfilesSuccess = {
|
||||
users: UserProfile[];
|
||||
error?: undefined;
|
||||
}
|
||||
|
||||
type Props = {
|
||||
buttonText: MessageDescriptor;
|
||||
componentId: string;
|
||||
currentUserId: string;
|
||||
getProfiles: () => Promise<getProfilesSuccess | getProfilesError>;
|
||||
handleRemoveProfile: (id: string) => void;
|
||||
handleSelectProfile: (user: UserProfile) => void;
|
||||
loading: boolean;
|
||||
maxSelectedUsers: number;
|
||||
onButtonTap: (selectedId?: {[id: string]: boolean}) => Promise<boolean>;
|
||||
page: MutableRefObject<number>;
|
||||
searchResults: UserProfile[];
|
||||
selectedIds: {[id: string]: UserProfile};
|
||||
setLoading: (loading: boolean) => void;
|
||||
teammateNameDisplay: string;
|
||||
term: string;
|
||||
tutorialWatched: boolean;
|
||||
}
|
||||
|
||||
function reduceProfiles(state: UserProfile[], action: {type: 'add'; values?: UserProfile[]}) {
|
||||
if (action.type === 'add' && action.values?.length) {
|
||||
return [...state, ...action.values];
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
const UsersModal = ({
|
||||
buttonText,
|
||||
componentId,
|
||||
currentUserId,
|
||||
getProfiles,
|
||||
handleRemoveProfile,
|
||||
handleSelectProfile,
|
||||
loading,
|
||||
maxSelectedUsers,
|
||||
onButtonTap,
|
||||
page,
|
||||
searchResults,
|
||||
selectedIds,
|
||||
setLoading,
|
||||
teammateNameDisplay,
|
||||
term,
|
||||
tutorialWatched,
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
const {formatMessage, locale} = useIntl();
|
||||
const mounted = useRef(false);
|
||||
const next = useRef(true);
|
||||
|
||||
const selectedCount = Object.keys(selectedIds).length;
|
||||
|
||||
const [startingButtonAction, setStartingButtonAction] = useState(false);
|
||||
const [profiles, dispatchProfiles] = useReducer(reduceProfiles, []);
|
||||
|
||||
const isSearch = Boolean(term);
|
||||
|
||||
const loadedProfiles = useCallback(({users}: {users?: UserProfile[]}) => {
|
||||
if (mounted.current) {
|
||||
if (users && !users.length) {
|
||||
next.current = false;
|
||||
}
|
||||
|
||||
page.current += 1;
|
||||
setLoading(false);
|
||||
dispatchProfiles({type: 'add', values: users});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleButtonTap = useCallback(async (selectedId?: {[id: string]: boolean}) => {
|
||||
if (startingButtonAction) {
|
||||
return;
|
||||
}
|
||||
|
||||
setStartingButtonAction(true);
|
||||
|
||||
const idsToUse = selectedId ? Object.keys(selectedId) : Object.keys(selectedIds);
|
||||
const success = idsToUse.length === 0 ? false : await onButtonTap();
|
||||
|
||||
if (success) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
setStartingButtonAction(false);
|
||||
}, [onButtonTap, selectedIds, startingButtonAction]);
|
||||
|
||||
const handleGetProfiles = useCallback(debounce(() => {
|
||||
if (next.current && !loading && !term && mounted.current) {
|
||||
setLoading(true);
|
||||
getProfiles().then(loadedProfiles);
|
||||
}
|
||||
}, 100), [getProfiles, loading, term]);
|
||||
|
||||
const data = useMemo(() => {
|
||||
if (isSearch) {
|
||||
const exactMatches: UserProfile[] = [];
|
||||
const filterByTerm = (p: UserProfile) => {
|
||||
if (selectedCount > 0 && p.id === currentUserId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p.username === term || p.username.startsWith(term)) {
|
||||
exactMatches.push(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const results = filterProfilesMatchingTerm(searchResults, term).filter(filterByTerm);
|
||||
return [...exactMatches, ...results];
|
||||
}
|
||||
return profiles;
|
||||
}, [isSearch && selectedCount, isSearch && searchResults, profiles, term]);
|
||||
|
||||
const updateNavigationButtons = useCallback(async (startEnabled: boolean) => {
|
||||
const closeIcon = await CompassIcon.getImageSource('close', 24, theme.sidebarHeaderTextColor);
|
||||
setButtons(componentId, {
|
||||
leftButtons: [{
|
||||
id: CLOSE_BUTTON,
|
||||
icon: closeIcon,
|
||||
testID: 'close.button',
|
||||
}],
|
||||
rightButtons: [{
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
id: ACTION_BUTTON,
|
||||
text: formatMessage(buttonText),
|
||||
showAsAction: 'always',
|
||||
enabled: startEnabled,
|
||||
testID: 'action.button',
|
||||
}],
|
||||
});
|
||||
}, [buttonText, locale, theme]);
|
||||
|
||||
useEffect(() => {
|
||||
mounted.current = true;
|
||||
updateNavigationButtons(false);
|
||||
handleGetProfiles();
|
||||
return () => {
|
||||
mounted.current = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const canStart = selectedCount > 0 && !startingButtonAction;
|
||||
updateNavigationButtons(canStart);
|
||||
}, [selectedCount > 0, startingButtonAction, updateNavigationButtons]);
|
||||
|
||||
useNavButtonPressed(ACTION_BUTTON, componentId, handleButtonTap, [handleButtonTap]);
|
||||
useNavButtonPressed(CLOSE_BUTTON, componentId, close, [close]);
|
||||
|
||||
if (startingButtonAction) {
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<Loading color={theme.centerChannelColor}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedCount > 0 &&
|
||||
<SelectedUsersPanel
|
||||
selectedIds={selectedIds}
|
||||
warnCount={maxSelectedUsers - 2}
|
||||
maxCount={maxSelectedUsers}
|
||||
onRemove={handleRemoveProfile}
|
||||
teammateNameDisplay={teammateNameDisplay}
|
||||
/>
|
||||
}
|
||||
<UserList
|
||||
currentUserId={currentUserId}
|
||||
fetchMore={handleGetProfiles}
|
||||
handleSelectProfile={handleSelectProfile}
|
||||
loading={loading}
|
||||
profiles={data}
|
||||
selectedIds={selectedIds}
|
||||
showNoResults={!loading && page?.current !== -1}
|
||||
teammateNameDisplay={teammateNameDisplay}
|
||||
term={term}
|
||||
testID='members_modal.user_list'
|
||||
tutorialWatched={tutorialWatched}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UsersModal;
|
||||
@@ -1,32 +1,47 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Keyboard, Platform, View} from 'react-native';
|
||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
import React, {useCallback, useRef, useState} from 'react';
|
||||
import {defineMessages, useIntl} from 'react-intl';
|
||||
import {Platform, SafeAreaView, StyleSheet, View} from 'react-native';
|
||||
|
||||
import {makeDirectChannel, makeGroupChannel} from '@actions/remote/channel';
|
||||
import {fetchProfiles, fetchProfilesInTeam, searchProfiles} from '@actions/remote/user';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import Loading from '@components/loading';
|
||||
import Search from '@components/search';
|
||||
import UsersModal from '@components/users_modal';
|
||||
import {General} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {debounce} from '@helpers/api/general';
|
||||
import useNavButtonPressed from '@hooks/navigation_button_pressed';
|
||||
import {t} from '@i18n';
|
||||
import {dismissModal, setButtons} from '@screens/navigation';
|
||||
import {alertErrorWithFallback} from '@utils/draft';
|
||||
import {changeOpacity, getKeyboardAppearanceFromTheme, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {displayUsername, filterProfilesMatchingTerm} from '@utils/user';
|
||||
import {changeOpacity, getKeyboardAppearanceFromTheme} from '@utils/theme';
|
||||
import {displayUsername} from '@utils/user';
|
||||
|
||||
import SelectedUsers from './selected_users';
|
||||
import UserList from './user_list';
|
||||
const style = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
searchBar: {
|
||||
marginLeft: 12,
|
||||
marginRight: Platform.select({ios: 4, default: 12}),
|
||||
marginVertical: 12,
|
||||
},
|
||||
});
|
||||
|
||||
const START_BUTTON = 'start-conversation';
|
||||
const CLOSE_BUTTON = 'close-dms';
|
||||
const messages = defineMessages({
|
||||
dm: {
|
||||
id: t('mobile.open_dm.error'),
|
||||
defaultMessage: "We couldn't open a direct message with {displayName}. Please check your connection and try again.",
|
||||
},
|
||||
gm: {
|
||||
id: t('mobile.open_gm.error'),
|
||||
defaultMessage: "We couldn't open a group message with those users. Please check your connection and try again.",
|
||||
},
|
||||
button: {
|
||||
id: t('mobile.create_direct_message.start'),
|
||||
defaultMessage: 'Start',
|
||||
},
|
||||
});
|
||||
|
||||
type Props = {
|
||||
componentId: string;
|
||||
@@ -34,51 +49,6 @@ type Props = {
|
||||
currentUserId: string;
|
||||
restrictDirectMessage: boolean;
|
||||
teammateNameDisplay: string;
|
||||
tutorialWatched: boolean;
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
Keyboard.dismiss();
|
||||
dismissModal();
|
||||
};
|
||||
|
||||
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
searchBar: {
|
||||
marginLeft: 12,
|
||||
marginRight: Platform.select({ios: 4, default: 12}),
|
||||
marginVertical: 12,
|
||||
},
|
||||
loadingContainer: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
height: 70,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
loadingText: {
|
||||
color: changeOpacity(theme.centerChannelColor, 0.6),
|
||||
},
|
||||
noResultContainer: {
|
||||
flexGrow: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
noResultText: {
|
||||
fontSize: 26,
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function reduceProfiles(state: UserProfile[], action: {type: 'add'; values?: UserProfile[]}) {
|
||||
if (action.type === 'add' && action.values?.length) {
|
||||
return [...state, ...action.values];
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
export default function CreateDirectMessage({
|
||||
@@ -87,56 +57,31 @@ export default function CreateDirectMessage({
|
||||
currentUserId,
|
||||
restrictDirectMessage,
|
||||
teammateNameDisplay,
|
||||
tutorialWatched,
|
||||
}: Props) {
|
||||
const serverUrl = useServerUrl();
|
||||
const theme = useTheme();
|
||||
const style = getStyleFromTheme(theme);
|
||||
const intl = useIntl();
|
||||
const {formatMessage} = intl;
|
||||
|
||||
const searchTimeoutId = useRef<NodeJS.Timeout | null>(null);
|
||||
const next = useRef(true);
|
||||
const page = useRef(-1);
|
||||
const mounted = useRef(false);
|
||||
|
||||
const [profiles, dispatchProfiles] = useReducer(reduceProfiles, []);
|
||||
const [searchResults, setSearchResults] = useState<UserProfile[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [term, setTerm] = useState('');
|
||||
const [startingConversation, setStartingConversation] = useState(false);
|
||||
const [selectedIds, setSelectedIds] = useState<{[id: string]: UserProfile}>({});
|
||||
const selectedCount = Object.keys(selectedIds).length;
|
||||
|
||||
const isSearch = Boolean(term);
|
||||
|
||||
const loadedProfiles = ({users}: {users?: UserProfile[]}) => {
|
||||
if (mounted.current) {
|
||||
if (users && !users.length) {
|
||||
next.current = false;
|
||||
}
|
||||
|
||||
page.current += 1;
|
||||
setLoading(false);
|
||||
dispatchProfiles({type: 'add', values: users});
|
||||
}
|
||||
};
|
||||
|
||||
const clearSearch = useCallback(() => {
|
||||
setTerm('');
|
||||
setSearchResults([]);
|
||||
}, []);
|
||||
|
||||
const getProfiles = useCallback(debounce(() => {
|
||||
if (next.current && !loading && !term && mounted.current) {
|
||||
setLoading(true);
|
||||
if (restrictDirectMessage) {
|
||||
fetchProfilesInTeam(serverUrl, currentTeamId, page.current + 1, General.PROFILE_CHUNK_SIZE).then(loadedProfiles);
|
||||
} else {
|
||||
fetchProfiles(serverUrl, page.current + 1, General.PROFILE_CHUNK_SIZE).then(loadedProfiles);
|
||||
}
|
||||
const getProfiles = useCallback(async () => {
|
||||
if (restrictDirectMessage) {
|
||||
return fetchProfilesInTeam(serverUrl, currentTeamId, page.current + 1, General.PROFILE_CHUNK_SIZE);
|
||||
}
|
||||
}, 100), [loading, isSearch, restrictDirectMessage, serverUrl, currentTeamId]);
|
||||
return fetchProfiles(serverUrl, page.current + 1, General.PROFILE_CHUNK_SIZE);
|
||||
}, [restrictDirectMessage, serverUrl, currentTeamId]);
|
||||
|
||||
const handleRemoveProfile = useCallback((id: string) => {
|
||||
const newSelectedIds = Object.assign({}, selectedIds);
|
||||
@@ -148,68 +93,30 @@ export default function CreateDirectMessage({
|
||||
|
||||
const createDirectChannel = useCallback(async (id: string): Promise<boolean> => {
|
||||
const user = selectedIds[id];
|
||||
|
||||
const displayName = displayUsername(user, intl.locale, teammateNameDisplay);
|
||||
|
||||
const result = await makeDirectChannel(serverUrl, id, displayName);
|
||||
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
intl,
|
||||
result.error,
|
||||
{
|
||||
id: 'mobile.open_dm.error',
|
||||
defaultMessage: "We couldn't open a direct message with {displayName}. Please check your connection and try again.",
|
||||
},
|
||||
{
|
||||
displayName,
|
||||
},
|
||||
);
|
||||
alertErrorWithFallback(intl, result.error, messages.dm, {displayName});
|
||||
}
|
||||
|
||||
return !result.error;
|
||||
}, [selectedIds, intl.locale, teammateNameDisplay, serverUrl]);
|
||||
|
||||
const createGroupChannel = useCallback(async (ids: string[]): Promise<boolean> => {
|
||||
const result = await makeGroupChannel(serverUrl, ids);
|
||||
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
intl,
|
||||
result.error,
|
||||
{
|
||||
id: t('mobile.open_gm.error'),
|
||||
defaultMessage: "We couldn't open a group message with those users. Please check your connection and try again.",
|
||||
},
|
||||
);
|
||||
alertErrorWithFallback(intl, result.error, messages.gm);
|
||||
}
|
||||
|
||||
return !result.error;
|
||||
}, [serverUrl]);
|
||||
|
||||
const startConversation = useCallback(async (selectedId?: {[id: string]: boolean}) => {
|
||||
if (startingConversation) {
|
||||
return;
|
||||
}
|
||||
|
||||
setStartingConversation(true);
|
||||
|
||||
const onButtonTap = useCallback(async (selectedId?: {[id: string]: boolean}) => {
|
||||
const idsToUse = selectedId ? Object.keys(selectedId) : Object.keys(selectedIds);
|
||||
let success;
|
||||
if (idsToUse.length === 0) {
|
||||
success = false;
|
||||
} else if (idsToUse.length > 1) {
|
||||
success = await createGroupChannel(idsToUse);
|
||||
} else {
|
||||
success = await createDirectChannel(idsToUse[0]);
|
||||
if (idsToUse.length > 1) {
|
||||
return createGroupChannel(idsToUse);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
close();
|
||||
} else {
|
||||
setStartingConversation(false);
|
||||
}
|
||||
}, [startingConversation, selectedIds, createGroupChannel, createDirectChannel]);
|
||||
return createDirectChannel(idsToUse[0]);
|
||||
}, [selectedIds, createGroupChannel, createDirectChannel]);
|
||||
|
||||
const handleSelectProfile = useCallback((user: UserProfile) => {
|
||||
if (selectedIds[user.id]) {
|
||||
@@ -221,8 +128,7 @@ export default function CreateDirectMessage({
|
||||
const selectedId = {
|
||||
[currentUserId]: true,
|
||||
};
|
||||
|
||||
startConversation(selectedId);
|
||||
onButtonTap(selectedId);
|
||||
} else {
|
||||
const wasSelected = selectedIds[user.id];
|
||||
|
||||
@@ -239,7 +145,7 @@ export default function CreateDirectMessage({
|
||||
|
||||
clearSearch();
|
||||
}
|
||||
}, [selectedIds, currentUserId, handleRemoveProfile, startConversation, clearSearch]);
|
||||
}, [clearSearch, currentUserId, handleRemoveProfile, onButtonTap, selectedIds]);
|
||||
|
||||
const searchUsers = useCallback(async (searchTerm: string) => {
|
||||
const lowerCasedTerm = searchTerm.toLowerCase();
|
||||
@@ -280,72 +186,6 @@ export default function CreateDirectMessage({
|
||||
}
|
||||
}, [searchUsers, clearSearch]);
|
||||
|
||||
const updateNavigationButtons = useCallback(async (startEnabled: boolean) => {
|
||||
const closeIcon = await CompassIcon.getImageSource('close', 24, theme.sidebarHeaderTextColor);
|
||||
setButtons(componentId, {
|
||||
leftButtons: [{
|
||||
id: CLOSE_BUTTON,
|
||||
icon: closeIcon,
|
||||
testID: 'close.create_direct_message.button',
|
||||
}],
|
||||
rightButtons: [{
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
id: START_BUTTON,
|
||||
text: formatMessage({id: 'mobile.create_direct_message.start', defaultMessage: 'Start'}),
|
||||
showAsAction: 'always',
|
||||
enabled: startEnabled,
|
||||
testID: 'create_direct_message.start.button',
|
||||
}],
|
||||
});
|
||||
}, [intl.locale, theme]);
|
||||
|
||||
useNavButtonPressed(START_BUTTON, componentId, startConversation, [startConversation]);
|
||||
useNavButtonPressed(CLOSE_BUTTON, componentId, close, [close]);
|
||||
|
||||
useEffect(() => {
|
||||
mounted.current = true;
|
||||
updateNavigationButtons(false);
|
||||
getProfiles();
|
||||
return () => {
|
||||
mounted.current = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const canStart = selectedCount > 0 && !startingConversation;
|
||||
updateNavigationButtons(canStart);
|
||||
}, [selectedCount > 0, startingConversation, updateNavigationButtons]);
|
||||
|
||||
const data = useMemo(() => {
|
||||
if (term) {
|
||||
const exactMatches: UserProfile[] = [];
|
||||
const filterByTerm = (p: UserProfile) => {
|
||||
if (selectedCount > 0 && p.id === currentUserId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p.username === term || p.username.startsWith(term)) {
|
||||
exactMatches.push(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const results = filterProfilesMatchingTerm(searchResults, term).filter(filterByTerm);
|
||||
return [...exactMatches, ...results];
|
||||
}
|
||||
return profiles;
|
||||
}, [term, isSearch && selectedCount, isSearch && searchResults, profiles]);
|
||||
|
||||
if (startingConversation) {
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<Loading color={theme.centerChannelColor}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={style.container}
|
||||
@@ -365,29 +205,23 @@ export default function CreateDirectMessage({
|
||||
value={term}
|
||||
/>
|
||||
</View>
|
||||
{selectedCount > 0 &&
|
||||
<SelectedUsers
|
||||
selectedIds={selectedIds}
|
||||
warnCount={General.MAX_USERS_IN_GM - 2}
|
||||
maxCount={General.MAX_USERS_IN_GM}
|
||||
onRemove={handleRemoveProfile}
|
||||
teammateNameDisplay={teammateNameDisplay}
|
||||
/>
|
||||
}
|
||||
<UserList
|
||||
<UsersModal
|
||||
page={page}
|
||||
buttonText={messages.button}
|
||||
componentId={componentId}
|
||||
currentUserId={currentUserId}
|
||||
getProfiles={getProfiles}
|
||||
handleRemoveProfile={handleRemoveProfile}
|
||||
handleSelectProfile={handleSelectProfile}
|
||||
loading={loading}
|
||||
profiles={data}
|
||||
maxSelectedUsers={General.MAX_USERS_IN_GM}
|
||||
onButtonTap={onButtonTap}
|
||||
searchResults={searchResults}
|
||||
selectedIds={selectedIds}
|
||||
showNoResults={!loading && page.current !== -1}
|
||||
setLoading={setLoading}
|
||||
teammateNameDisplay={teammateNameDisplay}
|
||||
fetchMore={getProfiles}
|
||||
term={term}
|
||||
testID='create_direct_message.user_list'
|
||||
tutorialWatched={tutorialWatched}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {General} from '@constants';
|
||||
import {observeProfileLongPresTutorial} from '@queries/app/global';
|
||||
import {observeConfigValue, observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeTeammateNameDisplay} from '@queries/servers/user';
|
||||
|
||||
@@ -24,7 +23,6 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
teammateNameDisplay: observeTeammateNameDisplay(database),
|
||||
currentUserId: observeCurrentUserId(database),
|
||||
currentTeamId: observeCurrentTeamId(database),
|
||||
tutorialWatched: observeProfileLongPresTutorial(),
|
||||
restrictDirectMessage,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user