Various fixes for Web App bots (#2102)
This commit is contained in:
parent
d7ebc691e2
commit
923c946167
@ -179,7 +179,7 @@ export async function requestWebView({
|
||||
startParam,
|
||||
themeParams: theme ? buildInputThemeParams(theme) : undefined,
|
||||
fromBotMenu: isFromBotMenu || undefined,
|
||||
platform: 'web',
|
||||
platform: 'webz',
|
||||
...(sendAs && { sendAs: buildInputPeer(sendAs.id, sendAs.accessHash) }),
|
||||
}));
|
||||
|
||||
@ -204,7 +204,7 @@ export async function requestSimpleWebView({
|
||||
url,
|
||||
bot: buildInputPeer(bot.id, bot.accessHash),
|
||||
themeParams: theme ? buildInputThemeParams(theme) : undefined,
|
||||
platform: 'web',
|
||||
platform: 'webz',
|
||||
}));
|
||||
|
||||
return result?.url;
|
||||
|
||||
@ -103,6 +103,9 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
const prevPopupParams = usePrevious(popupParams);
|
||||
const renderingPopupParams = popupParams || prevPopupParams;
|
||||
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const frameRef = useRef<HTMLIFrameElement>(null);
|
||||
|
||||
const lang = useLang();
|
||||
const {
|
||||
url, buttonText, queryId,
|
||||
@ -191,8 +194,8 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
]);
|
||||
|
||||
const {
|
||||
ref, reloadFrame, sendEvent, sendViewport, sendTheme,
|
||||
} = useWebAppFrame(isOpen, isSimple, handleEvent);
|
||||
reloadFrame, sendEvent, sendViewport, sendTheme,
|
||||
} = useWebAppFrame(frameRef, isOpen, isSimple, handleEvent);
|
||||
|
||||
const shouldShowMainButton = mainButton?.isVisible && mainButton.text.trim().length > 0;
|
||||
|
||||
@ -238,6 +241,10 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
});
|
||||
}, [sendEvent]);
|
||||
|
||||
const handlePopupModalClose = useCallback(() => {
|
||||
handlePopupClose();
|
||||
}, [handlePopupClose]);
|
||||
|
||||
// Notify view that height changed
|
||||
useOnChange(() => {
|
||||
setTimeout(() => {
|
||||
@ -427,13 +434,13 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
{isOpen && (
|
||||
<>
|
||||
<iframe
|
||||
ref={ref}
|
||||
className={buildClassName('web-app-frame', shouldDecreaseWebFrameSize && 'with-button')}
|
||||
src={url}
|
||||
title={`${bot?.firstName} Web App`}
|
||||
sandbox={SANDBOX_ATTRIBUTES}
|
||||
allow="camera; microphone; geolocation;"
|
||||
allowFullScreen
|
||||
ref={frameRef}
|
||||
/>
|
||||
<Button
|
||||
className={buildClassName(
|
||||
@ -465,7 +472,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
<Modal
|
||||
isOpen={Boolean(popupParams)}
|
||||
title={renderingPopupParams.title || NBSP}
|
||||
onClose={handlePopupClose}
|
||||
onClose={handlePopupModalClose}
|
||||
hasCloseButton
|
||||
className={buildClassName('web-app-popup', !renderingPopupParams.title?.trim().length && 'without-title')}
|
||||
>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import useWindowSize from '../../../hooks/useWindowSize';
|
||||
import { useCallback, useEffect, useRef } from '../../../lib/teact/teact';
|
||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||
import useWindowSize from '../../../hooks/useWindowSize';
|
||||
|
||||
export type PopupOptions = {
|
||||
title: string;
|
||||
@ -84,6 +84,7 @@ type WebAppOutboundEvent = {
|
||||
height: number;
|
||||
width?: number;
|
||||
is_expanded?: boolean;
|
||||
is_state_stable?: boolean;
|
||||
};
|
||||
} | {
|
||||
eventType: 'theme_changed';
|
||||
@ -141,10 +142,14 @@ const SCROLLBAR_STYLE = `* {
|
||||
background-color: transparent;
|
||||
}`;
|
||||
|
||||
const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event: WebAppInboundEvent) => void) => {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const ref = useRef<HTMLIFrameElement>(null);
|
||||
const useWebAppFrame = (
|
||||
ref: React.RefObject<HTMLIFrameElement>,
|
||||
isOpen: boolean,
|
||||
isSimpleView: boolean,
|
||||
onEvent: (event: WebAppInboundEvent) => void,
|
||||
) => {
|
||||
const ignoreEventsRef = useRef<boolean>(false);
|
||||
const lastFrameSizeRef = useRef<{ width: number; height: number; isResizing?: boolean }>();
|
||||
const windowSize = useWindowSize();
|
||||
|
||||
const reloadFrame = useCallback((url: string) => {
|
||||
@ -154,14 +159,14 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
|
||||
frame.addEventListener('load', () => {
|
||||
frame.src = url;
|
||||
}, { once: true });
|
||||
}, []);
|
||||
}, [ref]);
|
||||
|
||||
const sendEvent = useCallback((event: WebAppOutboundEvent) => {
|
||||
if (!ref.current?.contentWindow) return;
|
||||
ref.current.contentWindow.postMessage(JSON.stringify(event), '*');
|
||||
}, []);
|
||||
}, [ref]);
|
||||
|
||||
const sendViewport = useCallback(() => {
|
||||
const sendViewport = useCallback((isNonStable?: boolean) => {
|
||||
if (!ref.current) {
|
||||
return;
|
||||
}
|
||||
@ -172,9 +177,10 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
|
||||
width,
|
||||
height,
|
||||
is_expanded: true,
|
||||
is_state_stable: !isNonStable,
|
||||
},
|
||||
});
|
||||
}, [sendEvent]);
|
||||
}, [sendEvent, ref]);
|
||||
|
||||
const sendTheme = useCallback(() => {
|
||||
sendEvent({
|
||||
@ -201,7 +207,7 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
|
||||
const data = JSON.parse(event.data) as WebAppInboundEvent;
|
||||
// Handle some app requests here to simplify hook usage
|
||||
if (data.eventType === 'web_app_request_viewport') {
|
||||
sendViewport();
|
||||
sendViewport(windowSize.isResizing);
|
||||
}
|
||||
|
||||
if (data.eventType === 'web_app_request_theme') {
|
||||
@ -221,12 +227,14 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
|
||||
} catch (err) {
|
||||
// Ignore other messages
|
||||
}
|
||||
}, [isSimpleView, onEvent, sendCustomStyle, sendTheme, sendViewport]);
|
||||
}, [isSimpleView, onEvent, sendCustomStyle, sendTheme, sendViewport, windowSize]);
|
||||
|
||||
useEffect(() => {
|
||||
if (windowSize) {
|
||||
sendViewport();
|
||||
}
|
||||
const { width, height, isResizing } = windowSize;
|
||||
if (lastFrameSizeRef.current && lastFrameSizeRef.current.width === width
|
||||
&& lastFrameSizeRef.current.height === height && !lastFrameSizeRef.current.isResizing) return;
|
||||
lastFrameSizeRef.current = { width, height, isResizing };
|
||||
sendViewport(isResizing);
|
||||
}, [sendViewport, windowSize]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -238,11 +246,13 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
|
||||
if (isOpen && ref.current?.contentWindow) {
|
||||
sendViewport();
|
||||
ignoreEventsRef.current = false;
|
||||
} else {
|
||||
lastFrameSizeRef.current = undefined;
|
||||
}
|
||||
}, [isOpen, sendViewport]);
|
||||
}, [isOpen, sendViewport, ref]);
|
||||
|
||||
return {
|
||||
ref, sendEvent, reloadFrame, sendViewport, sendTheme,
|
||||
sendEvent, reloadFrame, sendViewport, sendTheme,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from '../lib/teact/teact';
|
||||
import { useEffect, useMemo, useState } from '../lib/teact/teact';
|
||||
import type { ApiDimensions } from '../api/types';
|
||||
|
||||
import { throttle } from '../util/schedulers';
|
||||
@ -12,6 +12,8 @@ const useWindowSize = () => {
|
||||
const [isResizing, setIsResizing] = useState(false);
|
||||
const setIsResizingDebounced = useDebouncedCallback(setIsResizing, [], THROTTLE, true);
|
||||
|
||||
const result = useMemo(() => ({ ...size, isResizing }), [isResizing, size]);
|
||||
|
||||
useEffect(() => {
|
||||
const throttledSetIsResizing = throttle(() => {
|
||||
setIsResizing(true);
|
||||
@ -34,7 +36,7 @@ const useWindowSize = () => {
|
||||
};
|
||||
}, [setIsResizingDebounced]);
|
||||
|
||||
return { ...size, isResizing };
|
||||
return result;
|
||||
};
|
||||
|
||||
export default useWindowSize;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user