mattermost-redux
Version:
Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client
423 lines (374 loc) • 12.8 kB
text/typescript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {GifTypes} from 'action_types';
import {Client4} from 'client';
import gfycatSdk from 'utils/gfycat_sdk';
import {DispatchFunc, GetStateFunc} from 'types/actions';
import {GlobalState} from 'types/store';
// APP PROPS
export function saveAppPropsRequest(props: any) {
return {
type: GifTypes.SAVE_APP_PROPS,
props,
};
}
export function saveAppProps(appProps: any) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatApiKey, GfycatApiSecret} = getState().entities.general.config;
gfycatSdk(GfycatApiKey!, GfycatApiSecret!).authenticate();
dispatch(saveAppPropsRequest(appProps));
};
}
// SEARCH
export function selectSearchText(searchText: string) {
return {
type: GifTypes.SELECT_SEARCH_TEXT,
searchText,
};
}
export function updateSearchText(searchText: string) {
return {
type: GifTypes.UPDATE_SEARCH_TEXT,
searchText,
};
}
export function searchBarTextSave(searchBarText: string) {
return {
type: GifTypes.SAVE_SEARCH_BAR_TEXT,
searchBarText,
};
}
export function invalidateSearchText(searchText: string) {
return {
type: GifTypes.INVALIDATE_SEARCH_TEXT,
searchText,
};
}
export function requestSearch(searchText: string) {
return {
type: GifTypes.REQUEST_SEARCH,
searchText,
};
}
export function receiveSearch({searchText, count, start, json}: {searchText: string; count: number; start: number; json: any}) {
return {
type: GifTypes.RECEIVE_SEARCH,
searchText,
...json,
count,
start,
currentPage: start / count,
receivedAt: Date.now(),
};
}
export function receiveSearchEnd(searchText: string) {
return {
type: GifTypes.RECEIVE_SEARCH_END,
searchText,
};
}
export function errorSearching(err: any, searchText: string) {
return {
type: GifTypes.SEARCH_FAILURE,
searchText,
err,
};
}
export function receiveCategorySearch({tagName, json}: {tagName: string; json: any}) {
return {
type: GifTypes.RECEIVE_CATEGORY_SEARCH,
searchText: tagName,
...json,
receiveAt: Date.now(),
};
}
export function clearSearchResults() {
return {
type: GifTypes.CLEAR_SEARCH_RESULTS,
};
}
export function requestSearchById(gfyId: string) {
return {
type: GifTypes.SEARCH_BY_ID_REQUEST,
payload: {
gfyId,
},
};
}
export function receiveSearchById(gfyId: string, gfyItem: any) {
return {
type: GifTypes.SEARCH_BY_ID_SUCCESS,
payload: {
gfyId,
gfyItem,
},
};
}
export function errorSearchById(err: any, gfyId: string) {
return {
type: GifTypes.SEARCH_BY_ID_FAILURE,
err,
gfyId,
};
}
export function searchScrollPosition(scrollPosition: number) {
return {
type: GifTypes.SAVE_SEARCH_SCROLL_POSITION,
scrollPosition,
};
}
export function searchPriorLocation(priorLocation: number) {
return {
type: GifTypes.SAVE_SEARCH_PRIOR_LOCATION,
priorLocation,
};
}
export function searchGfycat({searchText, count = 30, startIndex = 0}: { searchText: string; count?: number; startIndex?: number}) {
let start = startIndex;
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatApiKey, GfycatApiSecret} = getState().entities.general.config;
const {resultsByTerm} = getState().entities.gifs.search;
if (resultsByTerm[searchText]) {
start = resultsByTerm[searchText].start + count;
}
dispatch(requestSearch(searchText));
const sdk = gfycatSdk(GfycatApiKey!, GfycatApiSecret!);
sdk.authenticate();
return sdk.search({search_text: searchText, count, start}).then((json: any) => {
if (json.errorMessage) {
// There was no results before
if (resultsByTerm[searchText].items) {
dispatch(receiveSearchEnd(searchText));
} else {
dispatch(errorSearching(json, searchText));
}
} else {
dispatch(updateSearchText(searchText));
dispatch(cacheGifsRequest(json.gfycats));
dispatch(receiveSearch({searchText, count, start, json}));
const context = getState().entities.gifs.categories.tagsDict[searchText] ?
'category' :
'search';
Client4.trackEvent(
'gfycat',
'views',
{context, count: json.gfycats.length, keyword: searchText},
);
}
}).catch(
(err: any) => dispatch(errorSearching(err, searchText)),
);
};
}
export function searchCategory({tagName = '', gfyCount = 30, cursorPos = undefined}) {
let cursor = cursorPos;
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatApiKey, GfycatApiSecret} = getState().entities.general.config;
const {resultsByTerm} = getState().entities.gifs.search;
if (resultsByTerm[tagName]) {
cursor = resultsByTerm[tagName].cursor;
}
dispatch(requestSearch(tagName));
return gfycatSdk(GfycatApiKey!, GfycatApiSecret!).getTrendingCategories({tagName, gfyCount, cursor}).then(
(json: any) => {
if (json.errorMessage) {
if (resultsByTerm[tagName].gfycats) {
dispatch(receiveSearchEnd(tagName));
} else {
dispatch(errorSearching(json, tagName));
}
} else {
dispatch(updateSearchText(tagName));
dispatch(cacheGifsRequest(json.gfycats));
dispatch(receiveCategorySearch({tagName, json}));
Client4.trackEvent(
'gfycat',
'views',
{context: 'category', count: json.gfycats.length, keyword: tagName},
);
// preload categories list
if (tagName === 'trending') {
dispatch(requestCategoriesListIfNeeded() as any);
}
}
},
).catch((err: any) => dispatch(errorSearching(err, tagName)));
};
}
export function shouldSearch(state: GlobalState, searchText: string) {
const resultsByTerm = state.entities.gifs.search.resultsByTerm[searchText];
if (!resultsByTerm) {
return true;
} else if (resultsByTerm.isFetching) {
return false;
} else if (resultsByTerm.moreRemaining) {
return true;
}
return resultsByTerm.didInvalidate;
}
export function searchIfNeeded(searchText: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
if (shouldSearch(getState(), searchText)) {
if (searchText.toLowerCase() === 'trending') {
return dispatch(searchCategory({tagName: searchText}));
}
return dispatch(searchGfycat({searchText}));
}
return Promise.resolve();
};
}
export function searchIfNeededInitial(searchText: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
dispatch(updateSearchText(searchText));
if (shouldSearchInitial(getState(), searchText)) {
if (searchText.toLowerCase() === 'trending') {
return dispatch(searchCategory({tagName: searchText}));
}
return dispatch(searchGfycat({searchText}));
}
return Promise.resolve();
};
}
export function shouldSearchInitial(state: GlobalState, searchText: string) {
const resultsByTerm = state.entities.gifs.search.resultsByTerm[searchText];
if (!resultsByTerm) {
return true;
} else if (resultsByTerm.isFetching) {
return false;
}
return false;
}
export function searchById(gfyId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatApiKey, GfycatApiSecret} = getState().entities.general.config;
dispatch(requestSearchById(gfyId));
return gfycatSdk(GfycatApiKey!, GfycatApiSecret!).searchById({id: gfyId}).then(
(response: any) => {
dispatch(receiveSearchById(gfyId, response.gfyItem));
dispatch(cacheGifsRequest([response.gfyItem]));
},
).catch((err: any) => dispatch(errorSearchById(err, gfyId)));
};
}
export function shouldSearchById(state: GlobalState, gfyId: string) {
return !state.entities.gifs.cache.gifs[gfyId]; //TODO investigate, used to be !state.cache.gifs[gfyId];
}
export function searchByIdIfNeeded(gfyId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
if (shouldSearchById(getState(), gfyId)) {
return dispatch(searchById(gfyId));
}
return Promise.resolve(getState().entities.gifs.cache.gifs[gfyId]); //TODO: investigate, used to be getState().cache.gifs[gfyId]
};
}
export function saveSearchScrollPosition(scrollPosition: number) {
return (dispatch: DispatchFunc) => {
dispatch(searchScrollPosition(scrollPosition));
};
}
export function saveSearchPriorLocation(priorLocation: number) {
return (dispatch: DispatchFunc) => {
dispatch(searchPriorLocation(priorLocation));
};
}
export function searchTextUpdate(searchText: string) {
return (dispatch: DispatchFunc) => {
dispatch(updateSearchText(searchText));
};
}
export function saveSearchBarText(searchBarText: string) {
return (dispatch: DispatchFunc) => {
dispatch(searchBarTextSave(searchBarText));
};
}
// CATEGORIES
export function categoriesListRequest() {
return {
type: GifTypes.REQUEST_CATEGORIES_LIST,
};
}
export function categoriesListReceived(json: any) {
return {
type: GifTypes.CATEGORIES_LIST_RECEIVED,
...json,
};
}
export function categoriesListFailure(err: any) {
return {
type: GifTypes.CATEGORIES_LIST_FAILURE,
err,
};
}
export function requestCategoriesList({count = 60} = {}) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatApiKey, GfycatApiSecret} = getState().entities.general.config;
const state = getState().entities.gifs.categories;
if (!shouldRequestCategoriesList(state)) {
return Promise.resolve();
}
dispatch(categoriesListRequest());
const {cursor} = state;
const options = {
...(count && {count}),
...(cursor && {cursor}),
};
return gfycatSdk(GfycatApiKey!, GfycatApiSecret!).getCategories(options).then((json: any) => {
const newGfycats = json.tags.reduce((gfycats: any[], tag: any) => {
if (tag.gfycats[0] && tag.gfycats[0].width) {
return [...gfycats, ...tag.gfycats];
}
return gfycats;
}, []);
dispatch(cacheGifsRequest(newGfycats));
dispatch(categoriesListReceived(json));
}).catch(
(err: any) => {
dispatch(categoriesListFailure(err));
},
);
};
}
export function requestCategoriesListIfNeeded({
count,
} = {count: undefined}) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState().entities.gifs.categories;
if (state.tagsList && state.tagsList.length) {
return Promise.resolve();
}
return dispatch(requestCategoriesList({count}));
};
}
export function shouldRequestCategoriesList(state: {hasMore: boolean; isFetching: boolean; tagsList: any[]}) {
const {hasMore, isFetching, tagsList} = state;
if (!tagsList || !tagsList.length) {
return true;
} else if (isFetching) {
return false;
} else if (hasMore) {
return true;
}
return false;
}
// CACHE
export function cacheRequest() {
return {
type: GifTypes.CACHE_REQUEST,
payload: {
updating: true,
},
};
}
export function cacheGifs(gifs: any) {
return {
type: GifTypes.CACHE_GIFS,
gifs,
};
}
export function cacheGifsRequest(gifs: any) {
return async (dispatch: DispatchFunc) => {
dispatch(cacheRequest());
dispatch(cacheGifs(gifs));
return {data: true};
};
}