144 lines
3.7 KiB
TypeScript
144 lines
3.7 KiB
TypeScript
import React, {
|
|
FC, memo, useRef, useCallback,
|
|
} from '../../lib/teact/teact';
|
|
import { withGlobal } from '../../lib/teact/teactn';
|
|
|
|
import { GlobalActions } from '../../global/types';
|
|
import { ApiChat, ApiVideo } from '../../api/types';
|
|
|
|
import { IS_TOUCH_ENV } from '../../util/environment';
|
|
import {
|
|
selectCurrentGifSearch,
|
|
selectChat,
|
|
selectIsChatWithBot,
|
|
selectCurrentMessageList,
|
|
} from '../../modules/selectors';
|
|
import { getAllowedAttachmentOptions } from '../../modules/helpers';
|
|
import { pick } from '../../util/iteratees';
|
|
import buildClassName from '../../util/buildClassName';
|
|
import { useIntersectionObserver } from '../../hooks/useIntersectionObserver';
|
|
import useLang from '../../hooks/useLang';
|
|
import useHistoryBack from '../../hooks/useHistoryBack';
|
|
|
|
import InfiniteScroll from '../ui/InfiniteScroll';
|
|
import GifButton from '../common/GifButton';
|
|
import Loading from '../ui/Loading';
|
|
|
|
import './GifSearch.scss';
|
|
|
|
type OwnProps = {
|
|
onClose: NoneToVoidFunction;
|
|
isActive: boolean;
|
|
};
|
|
|
|
type StateProps = {
|
|
query?: string;
|
|
results?: ApiVideo[];
|
|
chat?: ApiChat;
|
|
isChatWithBot?: boolean;
|
|
};
|
|
|
|
type DispatchProps = Pick<GlobalActions, 'searchMoreGifs' | 'sendMessage' | 'setGifSearchQuery'>;
|
|
|
|
const PRELOAD_BACKWARDS = 96; // GIF Search bot results are multiplied by 24
|
|
const INTERSECTION_DEBOUNCE = 300;
|
|
|
|
const GifSearch: FC<OwnProps & StateProps & DispatchProps> = ({
|
|
onClose,
|
|
isActive,
|
|
query,
|
|
results,
|
|
chat,
|
|
isChatWithBot,
|
|
searchMoreGifs,
|
|
sendMessage,
|
|
setGifSearchQuery,
|
|
}) => {
|
|
// eslint-disable-next-line no-null/no-null
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
|
|
const {
|
|
observe: observeIntersection,
|
|
} = useIntersectionObserver({ rootRef: containerRef, debounceMs: INTERSECTION_DEBOUNCE });
|
|
|
|
const { canSendGifs } = getAllowedAttachmentOptions(chat, isChatWithBot);
|
|
|
|
const handleGifClick = useCallback((gif: ApiVideo) => {
|
|
if (canSendGifs) {
|
|
sendMessage({ gif });
|
|
}
|
|
|
|
if (IS_TOUCH_ENV) {
|
|
setGifSearchQuery({ query: undefined });
|
|
}
|
|
}, [canSendGifs, sendMessage, setGifSearchQuery]);
|
|
|
|
const lang = useLang();
|
|
|
|
useHistoryBack(isActive, onClose);
|
|
|
|
function renderContent() {
|
|
if (query === undefined) {
|
|
return undefined;
|
|
}
|
|
|
|
if (!results) {
|
|
return (
|
|
<Loading />
|
|
);
|
|
}
|
|
|
|
if (!results.length) {
|
|
return (
|
|
<p className="helper-text" dir="auto">{lang('NoGIFsFound')}</p>
|
|
);
|
|
}
|
|
|
|
return results.map((gif) => (
|
|
<GifButton
|
|
key={gif.id}
|
|
gif={gif}
|
|
observeIntersection={observeIntersection}
|
|
onClick={handleGifClick}
|
|
/>
|
|
));
|
|
}
|
|
|
|
const hasResults = Boolean(query !== undefined && results && results.length);
|
|
|
|
return (
|
|
<div className="GifSearch" dir={lang.isRtl ? 'rtl' : undefined}>
|
|
<InfiniteScroll
|
|
ref={containerRef}
|
|
className={buildClassName('gif-container custom-scroll', hasResults && 'grid')}
|
|
items={results}
|
|
itemSelector=".GifButton"
|
|
preloadBackwards={PRELOAD_BACKWARDS}
|
|
noFastList
|
|
onLoadMore={searchMoreGifs}
|
|
>
|
|
{renderContent()}
|
|
</InfiniteScroll>
|
|
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default memo(withGlobal(
|
|
(global): StateProps => {
|
|
const currentSearch = selectCurrentGifSearch(global);
|
|
const { query, results } = currentSearch || {};
|
|
const { chatId } = selectCurrentMessageList(global) || {};
|
|
const chat = chatId ? selectChat(global, chatId) : undefined;
|
|
const isChatWithBot = chat ? selectIsChatWithBot(global, chat) : undefined;
|
|
|
|
return {
|
|
query,
|
|
results,
|
|
chat,
|
|
isChatWithBot,
|
|
};
|
|
},
|
|
(setGlobal, actions): DispatchProps => pick(actions, ['searchMoreGifs', 'sendMessage', 'setGifSearchQuery']),
|
|
)(GifSearch));
|