124 lines
3.5 KiB
TypeScript
124 lines
3.5 KiB
TypeScript
import React, {
|
|
FC, memo, useEffect, useMemo,
|
|
} from '../../../lib/teact/teact';
|
|
import { withGlobal } from '../../../lib/teact/teactn';
|
|
|
|
import { GlobalActions } from '../../../global/types';
|
|
import { ApiMessage, ApiMessageEntityTypes, ApiWebPage } from '../../../api/types';
|
|
|
|
import { RE_LINK_TEMPLATE } from '../../../config';
|
|
import { selectNoWebPage } from '../../../modules/selectors';
|
|
import { pick } from '../../../util/iteratees';
|
|
import parseMessageInput from './helpers/parseMessageInput';
|
|
import useOnChange from '../../../hooks/useOnChange';
|
|
import useShowTransition from '../../../hooks/useShowTransition';
|
|
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
|
import buildClassName from '../../../util/buildClassName';
|
|
|
|
import WebPage from '../message/WebPage';
|
|
import Button from '../../ui/Button';
|
|
|
|
import './WebPagePreview.scss';
|
|
|
|
type OwnProps = {
|
|
chatId: number;
|
|
threadId: number;
|
|
messageText: string;
|
|
disabled?: boolean;
|
|
};
|
|
|
|
type StateProps = {
|
|
webPagePreview?: ApiWebPage;
|
|
noWebPage?: boolean;
|
|
};
|
|
type DispatchProps = Pick<GlobalActions, 'loadWebPagePreview' | 'clearWebPagePreview' | 'toggleMessageWebPage'>;
|
|
|
|
const RE_LINK = new RegExp(RE_LINK_TEMPLATE, 'i');
|
|
|
|
const WebPagePreview: FC<OwnProps & StateProps & DispatchProps> = ({
|
|
chatId,
|
|
threadId,
|
|
messageText,
|
|
disabled,
|
|
webPagePreview,
|
|
noWebPage,
|
|
loadWebPagePreview,
|
|
clearWebPagePreview,
|
|
toggleMessageWebPage,
|
|
}) => {
|
|
const link = useMemo(() => {
|
|
const { text, entities } = parseMessageInput(messageText);
|
|
|
|
const linkEntity = entities && entities.find(({ type }) => type === ApiMessageEntityTypes.TextUrl);
|
|
if (linkEntity) {
|
|
return linkEntity.url;
|
|
}
|
|
|
|
const textMatch = text.match(RE_LINK);
|
|
if (textMatch) {
|
|
return textMatch[0];
|
|
}
|
|
|
|
return undefined;
|
|
}, [messageText]);
|
|
|
|
useEffect(() => {
|
|
if (link) {
|
|
loadWebPagePreview({ text: link });
|
|
} else {
|
|
clearWebPagePreview();
|
|
toggleMessageWebPage({ chatId, threadId });
|
|
}
|
|
}, [chatId, toggleMessageWebPage, clearWebPagePreview, link, loadWebPagePreview, threadId]);
|
|
|
|
useOnChange(() => {
|
|
clearWebPagePreview();
|
|
toggleMessageWebPage({ chatId, threadId });
|
|
}, [chatId]);
|
|
|
|
const isShown = Boolean(webPagePreview && messageText.length && !noWebPage && !disabled);
|
|
const { shouldRender, transitionClassNames } = useShowTransition(isShown);
|
|
|
|
const renderingWebPage = useCurrentOrPrev(webPagePreview, true);
|
|
|
|
if (!shouldRender || !renderingWebPage) {
|
|
return undefined;
|
|
}
|
|
|
|
const handleClearWebpagePreview = () => {
|
|
toggleMessageWebPage({ chatId, threadId, noWebPage: true });
|
|
};
|
|
|
|
// TODO Refactor so `WebPage` can be used without message
|
|
const { photo, ...webPageWithoutPhoto } = renderingWebPage;
|
|
const messageStub = {
|
|
content: {
|
|
webPage: webPageWithoutPhoto,
|
|
},
|
|
} as ApiMessage;
|
|
|
|
return (
|
|
<div className={buildClassName('WebPagePreview', transitionClassNames)}>
|
|
<div>
|
|
<Button round faded color="translucent" ariaLabel="Clear Webpage Preview" onClick={handleClearWebpagePreview}>
|
|
<i className="icon-close" />
|
|
</Button>
|
|
<WebPage message={messageStub} inPreview />
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default memo(withGlobal<OwnProps>(
|
|
(global, { chatId, threadId }): StateProps => {
|
|
const noWebPage = selectNoWebPage(global, chatId, threadId);
|
|
return {
|
|
webPagePreview: global.webPagePreview,
|
|
noWebPage,
|
|
};
|
|
},
|
|
(setGlobal, actions): DispatchProps => pick(actions, [
|
|
'loadWebPagePreview', 'clearWebPagePreview', 'toggleMessageWebPage',
|
|
]),
|
|
)(WebPagePreview));
|