From 44c1b3d7b618754f82b104674b5aea3a6d8dabf5 Mon Sep 17 00:00:00 2001 From: Yannick Chiron Date: Thu, 10 Feb 2022 11:15:40 +0100 Subject: [PATCH] fix: Stabilize opening connectors on the HomeView #74 introduced the ability to open a connector from the cozy-store webview This implementation had a side effect as the requested connector was kept in the application state which would trigger the connector display after each re-render For example if the user opens a connector from the store, closes it and the navigate to cozy-drive, then when navigating back to the Home, the connector would be displayed again To prevent this we now keep track of the webview's url in real time and then use the navigation's `focus` and `blur` events to fix the rendered url on the native context We also clear the navigation `konnector` param when consumed. Which would prevent an unexpected re-render of the connector after closing it This new implementation does not need to inject a javascript chunk to handle the navigation, so we deleted `interceptHashAndNavigate` method --- src/components/webviews/CozyWebView.js | 9 ++-- .../webviews/jsInteractions/jsNavigation.js | 13 ------ src/libs/functions/routeHelpers.js | 18 ++++++++ src/screens/home/components/HomeView.js | 45 ++++++++++++++++--- 4 files changed, 63 insertions(+), 22 deletions(-) delete mode 100644 src/components/webviews/jsInteractions/jsNavigation.js create mode 100644 src/libs/functions/routeHelpers.js diff --git a/src/components/webviews/CozyWebView.js b/src/components/webviews/CozyWebView.js index ca4048ea8..73990e3f7 100644 --- a/src/components/webviews/CozyWebView.js +++ b/src/components/webviews/CozyWebView.js @@ -6,7 +6,6 @@ import {useSession} from '../../hooks/useSession.js' import {jsCozyGlobal} from './jsInteractions/jsCozyInjection' import {jsLogInterception, tryConsole} from './jsInteractions/jsLogInterception' -import {interceptHashAndNavigate} from './jsInteractions/jsNavigation' const log = Minilog('CozyWebView') @@ -18,6 +17,7 @@ const CozyWebView = ({ onMessage: parentOnMessage, logId = '', source, + trackWebviewInnerUri, ...rest }) => { const [ref, setRef] = useState('') @@ -60,8 +60,6 @@ const CozyWebView = ({ })(); ` - interceptHashAndNavigate(source.uri, ref, log, logId) - return uri ? ( { + if (trackWebviewInnerUri) { + trackWebviewInnerUri(nativeEvent.url) + } + }} onMessage={async m => { tryConsole(m, log, logId) diff --git a/src/components/webviews/jsInteractions/jsNavigation.js b/src/components/webviews/jsInteractions/jsNavigation.js deleted file mode 100644 index cc05201c0..000000000 --- a/src/components/webviews/jsInteractions/jsNavigation.js +++ /dev/null @@ -1,13 +0,0 @@ -export const interceptHashAndNavigate = (uri, webviewRef, logger, logId) => { - const url = new URL(uri) - - if (url.hash && webviewRef) { - logger.info(`[Native ${logId}] Redirect webview to ${url.hash}`) - webviewRef.injectJavaScript(` - (function() { - window.location.hash = '${url.hash}'; - true; - })(); - `) - } -} diff --git a/src/libs/functions/routeHelpers.js b/src/libs/functions/routeHelpers.js new file mode 100644 index 000000000..007094afd --- /dev/null +++ b/src/libs/functions/routeHelpers.js @@ -0,0 +1,18 @@ +import {get} from 'lodash' + +/** + * Retrieve the specified route parameter and remove it from the navigation state + * @param {string} paramName - Name of the parameter to retrieve + * @param {*} route - Application's route + * @param {*} navigation - Application's navigation + * @returns the route parameter's value + */ +export const consumeRouteParameter = (paramName, route, navigation) => { + const param = get(route, `params.${paramName}`) + + if (param) { + navigation.setParams({[paramName]: undefined}) + } + + return param +} diff --git a/src/screens/home/components/HomeView.js b/src/screens/home/components/HomeView.js index ea8cb6fb4..9745c5d2c 100644 --- a/src/screens/home/components/HomeView.js +++ b/src/screens/home/components/HomeView.js @@ -5,13 +5,45 @@ import {useNativeIntent} from 'cozy-intent' import {useSession} from '../../../hooks/useSession' import CozyWebView from '../../../components/webviews/CozyWebView' +import {consumeRouteParameter} from '../../../libs/functions/routeHelpers' const HomeView = ({route, navigation, setLauncherContext}) => { const client = useClient() const [uri, setUri] = useState('') + const [trackedWebviewInnerUri, setTrackedWebviewInnerUri] = useState('') const nativeIntent = useNativeIntent() const session = useSession() + React.useEffect(() => { + const unsubscribe = navigation.addListener('blur', () => { + setUri(trackedWebviewInnerUri) + }) + + return unsubscribe + }, [navigation, uri, trackedWebviewInnerUri]) + + React.useEffect(() => { + const unsubscribe = navigation.addListener('focus', () => { + if (uri) { + const konnectorParam = consumeRouteParameter( + 'konnector', + route, + navigation, + ) + + if (konnectorParam) { + const url = new URL(uri) + url.hash = `/connected/${konnectorParam}` + + const targetUri = url.toString() + setUri(targetUri) + } + } + }) + + return unsubscribe + }, [navigation, route, uri]) + useEffect(() => { const {shouldCreateSession, handleCreateSession, consumeSessionToken} = session @@ -39,13 +71,14 @@ const HomeView = ({route, navigation, setLauncherContext}) => { } }, [uri, client, route, nativeIntent, navigation, session]) - const konnectorParam = get(route, 'params.konnector') - const targetUri = - uri && konnectorParam ? `${uri}connected/${konnectorParam}` : uri - - return targetUri ? ( + return uri ? ( { + if (webviewInneruri !== trackedWebviewInnerUri) { + setTrackedWebviewInnerUri(webviewInneruri) + } + }} navigation={navigation} logId="HomeView" onMessage={async m => {