Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change routing in react-native so that I can trap the back button, handle linking, etc from within the react-native app. #10451

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import useUserStore from 'client/scripts/state/ui/user';
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

interface ReactNativeWebView {
// allows us to send messages to ReactNative.
Expand Down Expand Up @@ -31,6 +32,26 @@ type UserInfo = {
// darkMode: 'dark' | 'light';
};

type NavigateToLink = {
type: 'navigate-to-link';
link: string;
};

function isNavigateToLink(data: object): data is NavigateToLink {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (data as any).type === 'navigate-to-link';
}

type NavigateBack = {
type: 'navigate-back';
link: string;
};

function isNavigateBack(data: object): data is NavigateBack {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (data as any).type === 'navigate-back';
}

/**
* This acts as a bridge between the react-native client (mobile app) and our
* webapp. Notifications only work with a userId and the react-native client
Expand All @@ -44,9 +65,34 @@ type UserInfo = {
*/
export const ReactNativeBridge = () => {
const user = useUserStore();
const navigate = useNavigate();

const [userInfo, setUserInfo] = useState<UserInfo | null>(null);

const handleMessage = useCallback(
(message: MessageEvent) => {
const obj = messageToObject(message.data);
if (obj && typeof message.data === 'object') {
if (isNavigateToLink(obj)) {
navigate(getPathAndQuery(obj.link));
}

if (isNavigateBack(obj)) {
navigate(-1);
}
}
},
[navigate],
);

useEffect(() => {
window.addEventListener('message', handleMessage);

return () => {
window.removeEventListener('message', handleMessage);
};
}, [handleMessage]);

useEffect(() => {
if (user.id !== userInfo?.userId) {
setUserInfo({
Expand All @@ -70,3 +116,15 @@ export const ReactNativeBridge = () => {

return null;
};

function messageToObject(message: string | object): object {
return typeof message === 'string' ? JSON.parse(message) : message;
}

function getPathAndQuery(url: string): string {
// only navigate with the path and query because we don't want to include
// the host portion as a notification could be from the official common.xyz
// site but we might be using frack for testing.
const parsedUrl = new URL(url);
return `${parsedUrl.pathname}${parsedUrl.search}`;
}
Loading