mattermost-mobile/app/actions/remote/search.ts
Kyriakos Z 2645f7e66e
MM-39710: saved posts screen and DB (#6020)
* MM-39710: saved posts screen and DB

- Adds ids of saved posts to the systems table, as we do with recent
mentions.
- Adds a new remote action to fetch saved posts (getFlaggedPosts).
- Adds a new screen to display those in a mobile.
- Displays saved posts in the tablet view next to profile card.

* Uses Preferences instead of System table

Renames to saved posts wherever possible

* Adds text to localization file

* Fixes fetching/saving saved posts

* Refactor mini post to components folder

* Fixes hooks dependencies according to review

* Removes unnecessary 'withObservables'

* Small refactor

* Satisfies linter

* Adds empty state

And fixes empty state icon to be theme sensitive.
Both recent_mentions and saved_posts.

* Fixes empty screen's alignment

* Add missing preference

* add missing translation strings

* remove unused database type definition

* Fetch newly saved post

* Fix return type for client.getSavedPosts

* Remove usage of lodash compose

* Rename get remote actions to fetch

* Include close button for savedPost modal

* fix tablet view for SavePosts and use lottie loading indicator

* Render post with content for save posts and recent mentions

* post list viewable items type definition

* Add layout width to post content for saved post screen

* Use PostWithChannel and viewableItems for saved posts and recent mentions

* Layout margin of 20

* openGraphImage margin

* Fix openGraphImage display

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2022-03-12 16:40:24 -03:00

138 lines
4.3 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {processPostsFetched} from '@actions/local/post';
import {SYSTEM_IDENTIFIERS} from '@constants/database';
import DatabaseManager from '@database/manager';
import NetworkManager from '@init/network_manager';
import {prepareMissingChannelsForAllTeams} from '@queries/servers/channel';
import {queryCurrentUser} from '@queries/servers/user';
import {fetchPostAuthors, fetchMissingChannelsFromPosts} from './post';
import {forceLogoutIfNecessary} from './session';
import type {Client} from '@client/rest';
import type Model from '@nozbe/watermelondb/Model';
type PostSearchRequest = {
error?: unknown;
order?: string[];
posts?: Post[];
}
export async function fetchRecentMentions(serverUrl: string): Promise<PostSearchRequest> {
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
if (!operator) {
return {error: `${serverUrl} database not found`};
}
let client: Client;
try {
client = NetworkManager.getClient(serverUrl);
} catch (error) {
return {error};
}
let posts: Record<string, Post> = {};
let postsArray: Post[] = [];
let order: string[] = [];
try {
const currentUser = await queryCurrentUser(operator.database);
if (!currentUser) {
return {
posts: [],
order: [],
};
}
const terms = currentUser.userMentionKeys.map(({key}) => key).join(' ').trim() + ' ';
const data = await client.searchPosts('', terms, true);
posts = data.posts || {};
order = data.order || [];
const promises: Array<Promise<Model[]>> = [];
postsArray = order.map((id) => posts[id]);
const mentions: IdValue = {
id: SYSTEM_IDENTIFIERS.RECENT_MENTIONS,
value: JSON.stringify(order),
};
promises.push(operator.handleSystem({
systems: [mentions],
prepareRecordsOnly: true,
}));
if (postsArray.length) {
const {authors} = await fetchPostAuthors(serverUrl, postsArray, true);
const {channels, channelMemberships} = await fetchMissingChannelsFromPosts(serverUrl, postsArray, true) as {channels: Channel[]; channelMemberships: ChannelMembership[]};
if (authors?.length) {
promises.push(
operator.handleUsers({
users: authors,
prepareRecordsOnly: true,
}),
);
}
if (channels?.length && channelMemberships?.length) {
const channelPromises = prepareMissingChannelsForAllTeams(operator, channels, channelMemberships) as Array<Promise<Model[]>>;
if (channelPromises && channelPromises.length) {
promises.push(...channelPromises);
}
}
promises.push(
operator.handlePosts({
actionType: '',
order: [],
posts: postsArray,
previousPostId: '',
prepareRecordsOnly: true,
}),
);
}
const modelArrays = await Promise.all(promises);
const models = modelArrays.flatMap((mdls) => {
if (!mdls || !mdls.length) {
return [];
}
return mdls;
});
if (models.length) {
await operator.batchRecords(models);
}
} catch (error) {
forceLogoutIfNecessary(serverUrl, error as ClientErrorProps);
return {error};
}
return {
order,
posts: postsArray,
};
}
export const searchPosts = async (serverUrl: string, params: PostSearchParams): Promise<PostSearchRequest> => {
let client: Client;
try {
client = NetworkManager.getClient(serverUrl);
} catch (error) {
return {error};
}
let data;
try {
data = await client.searchPosts('', params.terms, params.is_or_search);
} catch (error) {
forceLogoutIfNecessary(serverUrl, error as ClientErrorProps);
return {error};
}
return processPostsFetched(serverUrl, '', data, false);
};