@talkjs/react-native
Version:
Official TalkJS SDK for React Native
198 lines (190 loc) • 7.29 kB
JavaScript
;
import { getNotificationHandler } from './index';
import { hasIdOnly } from './User';
import React, { useMemo, useRef, useState, useEffect, forwardRef, useImperativeHandle, useCallback } from 'react';
import { ON_MESSAGE_EVENT, SESSION, TOKEN_FETCHER_EVENT, UI_MOUNTED_MESSAGE, UNREADS_CHANGE_EVENT, VALID_CREDENTIALS_EVENT, WEBVIEW_ERROR, WEBVIEW_LOADED_MESSAGE } from './constants';
import { WebView } from './WebView';
import { CustomHandlers, TalkHandlers } from './Handlers';
import { Platform, StatusBar } from 'react-native';
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
const SessionContext = /*#__PURE__*/React.createContext(null);
function Session(props, ref) {
const webViewRef = useRef(null);
const pendingScripts = useRef([]);
const isWebViewLoadedRef = useRef(false);
const [isHeadless, setIsHeadless] = useState(true);
const [disableZoom, setDisableZoom] = useState(false);
const [keyboardVerticalOffset, setKeyboardVerticalOffset] = useState(Platform.OS === 'ios' ? 95 : 55 + (StatusBar.currentHeight ?? 35));
const [hideKeyboardAccessoryView, setHideKeyboardAccessoryView] = useState(false);
const customHandlers = useMemo(() => new CustomHandlers(), []);
useEffect(() => {
customHandlers.add(WEBVIEW_LOADED_MESSAGE, () => {
isWebViewLoadedRef.current = true;
pendingScripts.current.length = 0; // Clear the array.
});
}, [customHandlers]);
const injectJavaScript = useCallback(javascript => {
let result = javascript;
if (__DEV__) {
result = `
try {
${javascript}
} catch (e) {
sendToReactNative('${WEBVIEW_ERROR}', e.message);
}
true;`;
}
if (isWebViewLoadedRef.current) {
// This is undefined when the component is being unmounted.
webViewRef.current?.injectJavaScript(result);
} else {
pendingScripts.current.push(result);
}
}, [isWebViewLoadedRef, webViewRef]);
const talkHandlers = useMemo(() => new TalkHandlers(injectJavaScript), [injectJavaScript]);
let hasValidCredentialsResolver;
useEffect(() => {
customHandlers.add(VALID_CREDENTIALS_EVENT, result => {
hasValidCredentialsResolver(result);
hasValidCredentialsResolver = undefined;
});
// This means that there is a UI present, hence we don't need to be headless
customHandlers.add(UI_MOUNTED_MESSAGE, () => setIsHeadless(false));
}, []);
const context = useMemo(() => {
const me = hasIdOnly(props.me) ? props.me.id : props.me;
// If the user passes just a user ID, then we assume they either have
// browser synchronization off or they have already created the user some
// other way.
let userSynchronizationString = '';
if (typeof me !== 'string') {
userSynchronizationString = `
${SESSION}.currentUser.createIfNotExists({ name: ${JSON.stringify(me.name)} });
`;
}
let tokenFetcherString = '';
if (props.tokenFetcher) {
tokenFetcherString = `
window.sessionOptions['tokenFetcher'] = async () => {
const tokenFetcherPromise = new Promise((resolve) => {
window.tokenFetcherResolve = resolve;
});
sendToReactNative('${TOKEN_FETCHER_EVENT}');
return tokenFetcherPromise;
};
`;
customHandlers.add(TOKEN_FETCHER_EVENT, async () => {
const token = await props.tokenFetcher();
webViewRef.current.injectJavaScript(`window.tokenFetcherResolve(${JSON.stringify(token)}); true;`);
});
}
const javascript = `
if (${SESSION}) {
${SESSION}.destroy();
}
window.sessionOptions = {
appId: ${JSON.stringify(props.appId)},
me: new Talk.User(${JSON.stringify(me)}),
token: ${JSON.stringify(props.token)},
signature: ${JSON.stringify(props.signature)}
};
${tokenFetcherString}
${SESSION} = new Talk.Session(sessionOptions);
${userSynchronizationString}
true;
`;
injectJavaScript(javascript);
const session = {
appId: props.appId,
me: props.me,
token: props.token,
tokenFetcher: props.tokenFetcher,
signature: props.signature
};
return {
session,
customHandlers,
talkHandlers,
injectJavaScript,
setDisableZoom,
setKeyboardVerticalOffset,
setHideKeyboardAccessoryView
};
}, [props.appId, props.me, props.signature, props.token, props.tokenFetcher, injectJavaScript]);
useEffect(() => {
const notificationHandler = getNotificationHandler();
if (notificationHandler) {
// Push notification registration
if (props.enablePushNotifications === true) {
notificationHandler._getTokenPromise().then(() => {
const deviceToken = notificationHandler.deviceToken;
if (deviceToken.pushRegistrationId) {
injectJavaScript(`${SESSION}.setPushRegistration(${JSON.stringify(deviceToken)});true;`);
}
});
} else if (props.enablePushNotifications === false) {
injectJavaScript(`${SESSION}.clearPushRegistrations(); true;`);
}
}
}, [props.enablePushNotifications, context.session]);
useEffect(() => {
if (props.onMessage) {
const subscription = talkHandlers.add(ON_MESSAGE_EVENT, SESSION, props.onMessage);
return () => subscription.unsubscribe();
}
return;
}, [props.onMessage, context.session, talkHandlers]);
useEffect(() => {
if (props.onUnreadsChange) {
const subscription = talkHandlers.add(UNREADS_CHANGE_EVENT, SESSION, props.onUnreadsChange);
return () => subscription.unsubscribe();
}
return;
}, [props.onUnreadsChange, context.session, talkHandlers]);
useImperativeHandle(ref, () => ({
hasValidCredentials() {
return new Promise(resolve => {
hasValidCredentialsResolver = resolve;
injectJavaScript(`
${SESSION}.hasValidCredentials().then((result) => {
sendToReactNative('${VALID_CREDENTIALS_EVENT}', result);
});
true;
`);
});
},
clearPushRegistrations() {
injectJavaScript(`${SESSION}.clearPushRegistrations(); true;`);
},
setPushRegistration(token) {
injectJavaScript(`
${SESSION}.setPushRegistration(${JSON.stringify(token)});
true;
`);
},
unsetPushRegistration(token) {
injectJavaScript(`
${SESSION}.unsetPushRegistration(${JSON.stringify(token)});
true;
`);
}
}), [injectJavaScript]);
return /*#__PURE__*/_jsxs(_Fragment, {
children: [/*#__PURE__*/_jsx(WebView, {
ref: webViewRef,
customHandlers: customHandlers,
talkHandlers: talkHandlers,
isHeadless: isHeadless,
disableZoom: disableZoom,
pendingScripts: pendingScripts.current,
keyboardVerticalOffset: keyboardVerticalOffset,
hideKeyboardAccessoryView: hideKeyboardAccessoryView
}), /*#__PURE__*/_jsx(SessionContext.Provider, {
value: context,
children: props.children
})]
});
}
const forwardedSession = /*#__PURE__*/forwardRef(Session);
export { forwardedSession as Session, SessionContext };
//# sourceMappingURL=Session.js.map