forked from Ivasoft/mattermost-mobile
Use local channels on channel autocomplete (#6272)
* Use local channels on channel autocomplete * Only load local channels on demand
This commit is contained in:
committed by
GitHub
parent
a4674915c1
commit
7e27113f61
@@ -12,10 +12,14 @@ import {General} from '@constants';
|
||||
import {CHANNEL_MENTION_REGEX, CHANNEL_MENTION_SEARCH_REGEX} from '@constants/autocomplete';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import useDidUpdate from '@hooks/did_update';
|
||||
import {t} from '@i18n';
|
||||
import {queryAllChannelsForTeam} from '@queries/servers/channel';
|
||||
import {getCurrentTeamId} from '@queries/servers/system';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type MyChannelModel from '@typings/database/models/servers/my_channel';
|
||||
|
||||
const keyExtractor = (item: Channel) => {
|
||||
@@ -48,9 +52,9 @@ const getMatchTermForChannelMention = (() => {
|
||||
};
|
||||
})();
|
||||
|
||||
const reduceChannelsForSearch = (channels: Channel[], members: MyChannelModel[]) => {
|
||||
const reduceChannelsForSearch = (channels: Array<Channel | ChannelModel>, members: MyChannelModel[]) => {
|
||||
const memberIds = new Set(members.map((m) => m.id));
|
||||
return channels.reduce<Channel[][]>(([pubC, priC, dms], c) => {
|
||||
return channels.reduce<Array<Array<Channel | ChannelModel>>>(([pubC, priC, dms], c) => {
|
||||
switch (c.type) {
|
||||
case General.OPEN_CHANNEL:
|
||||
if (memberIds.has(c.id)) {
|
||||
@@ -68,9 +72,9 @@ const reduceChannelsForSearch = (channels: Channel[], members: MyChannelModel[])
|
||||
}, [[], [], []]);
|
||||
};
|
||||
|
||||
const reduceChannelsForAutocomplete = (channels: Channel[], members: MyChannelModel[]) => {
|
||||
const reduceChannelsForAutocomplete = (channels: Array<Channel | ChannelModel>, members: MyChannelModel[]) => {
|
||||
const memberIds = new Set(members.map((m) => m.id));
|
||||
return channels.reduce<Channel[][]>(([myC, otherC], c) => {
|
||||
return channels.reduce<Array<Array<Channel | ChannelModel>>>(([myC, otherC], c) => {
|
||||
if (memberIds.has(c.id)) {
|
||||
myC.push(c);
|
||||
} else {
|
||||
@@ -80,7 +84,7 @@ const reduceChannelsForAutocomplete = (channels: Channel[], members: MyChannelMo
|
||||
}, [[], []]);
|
||||
};
|
||||
|
||||
const makeSections = (channels: Channel[], myMembers: MyChannelModel[], isSearch = false) => {
|
||||
const makeSections = (channels: Array<Channel | ChannelModel>, myMembers: MyChannelModel[], isSearch = false) => {
|
||||
const newSections = [];
|
||||
if (isSearch) {
|
||||
const [publicChannels, privateChannels, directAndGroupMessages] = reduceChannelsForSearch(channels, myMembers);
|
||||
@@ -143,6 +147,14 @@ const makeSections = (channels: Channel[], myMembers: MyChannelModel[], isSearch
|
||||
|
||||
return newSections;
|
||||
};
|
||||
|
||||
const filterLocalResults = (channels: ChannelModel[], term: string) => {
|
||||
return channels.filter((c) =>
|
||||
c.name.toLowerCase().startsWith(term) ||
|
||||
c.displayName.toLowerCase().startsWith(term),
|
||||
);
|
||||
};
|
||||
|
||||
type Props = {
|
||||
cursorPosition: number;
|
||||
isSearch: boolean;
|
||||
@@ -163,8 +175,19 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
||||
};
|
||||
});
|
||||
|
||||
const getAllChannels = async (serverUrl: string) => {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl]?.database;
|
||||
if (!database) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const teamId = await getCurrentTeamId(database);
|
||||
return queryAllChannelsForTeam(database, teamId).fetch();
|
||||
};
|
||||
|
||||
const emptySections: Array<SectionListData<Channel>> = [];
|
||||
const emptyChannels: Channel[] = [];
|
||||
const emptyModelList: ChannelModel[] = [];
|
||||
|
||||
const ChannelMention = ({
|
||||
cursorPosition,
|
||||
@@ -180,11 +203,14 @@ const ChannelMention = ({
|
||||
const theme = useTheme();
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
||||
const [sections, setSections] = useState<Array<SectionListData<Channel>>>(emptySections);
|
||||
const [sections, setSections] = useState<Array<SectionListData<(Channel | ChannelModel)>>>(emptySections);
|
||||
const [channels, setChannels] = useState<Channel[]>(emptyChannels);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [noResultsTerm, setNoResultsTerm] = useState<string|null>(null);
|
||||
const [localCursorPosition, setLocalCursorPosition] = useState(cursorPosition); // To avoid errors due to delay between value changes and cursor position changes.
|
||||
const [useLocal, setUseLocal] = useState(true);
|
||||
const [localChannels, setlocalChannels] = useState<ChannelModel[]>();
|
||||
const [filteredLocalChannels, setFilteredLocalChannels] = useState(emptyModelList);
|
||||
|
||||
const listStyle = useMemo(() =>
|
||||
[style.listView, {maxHeight: maxListHeight}]
|
||||
@@ -192,8 +218,18 @@ const ChannelMention = ({
|
||||
|
||||
const runSearch = useMemo(() => debounce(async (sUrl: string, term: string) => {
|
||||
setLoading(true);
|
||||
const {channels: receivedChannels} = await searchChannels(sUrl, term);
|
||||
if (receivedChannels) {
|
||||
const {channels: receivedChannels, error} = await searchChannels(sUrl, term);
|
||||
setUseLocal(Boolean(error));
|
||||
|
||||
if (error) {
|
||||
let fallbackChannels = localChannels;
|
||||
if (!fallbackChannels) {
|
||||
fallbackChannels = await getAllChannels(sUrl);
|
||||
setlocalChannels(fallbackChannels);
|
||||
}
|
||||
const filteredChannels = filterLocalResults(fallbackChannels, term);
|
||||
setFilteredLocalChannels(filteredChannels.length ? filteredChannels : emptyModelList);
|
||||
} else if (receivedChannels) {
|
||||
setChannels(receivedChannels.length ? receivedChannels : emptyChannels);
|
||||
}
|
||||
setLoading(false);
|
||||
@@ -201,6 +237,7 @@ const ChannelMention = ({
|
||||
|
||||
const matchTerm = getMatchTermForChannelMention(value.substring(0, localCursorPosition), isSearch);
|
||||
const resetState = () => {
|
||||
setFilteredLocalChannels(emptyModelList);
|
||||
setChannels(emptyChannels);
|
||||
setSections(emptySections);
|
||||
runSearch.cancel();
|
||||
@@ -285,7 +322,7 @@ const ChannelMention = ({
|
||||
}, [matchTerm]);
|
||||
|
||||
useDidUpdate(() => {
|
||||
const newSections = makeSections(channels, myMembers, isSearch);
|
||||
const newSections = makeSections(useLocal ? filteredLocalChannels : channels, myMembers, isSearch);
|
||||
const nSections = newSections.length;
|
||||
|
||||
if (!loading && !nSections && noResultsTerm == null) {
|
||||
|
||||
Reference in New Issue
Block a user