@polls-platform/react-native
Version:
React Native SDK for Polls Platform
281 lines (238 loc) • 8.14 kB
JavaScript
// react
import React from 'react';
import { Animated, AppState, StyleSheet, View } from 'react-native'; // @polls-platform/core
import { ANIMATION_DURATION, REFRESH_POLL_AGE_SECONDS, WEBVIEW_ORIGIN_WHITELIST, getConfig, getThemeProperties, getThemeFromPollUrl, setPollUrlParams, EmbeddedMessage, EmbeddedMessageEvent, OpenPollFlow, Theme, constructPollUrl, isPollSourcePollId } from '@polls-platform/core/built/internal'; // @polls-platform/react-native
import { LoadingView, getEmbeddedState } from '../../internal'; // third party dependencies
import { WebView } from 'react-native-webview';
/**
* The `PollView` component is used for both creating and opening polls.
* For more information, go to https://docs.pollsplatform.com/react-native.
* Before navigating the user to this screen, you must have a poll URL.
* You can create a poll using the `createPoll` and `createPollAsync` functions
* which will respond with a URL that can be passed here.
* Or if you already have the URL of an existing poll you can pass it
* @category 3. PollView
*/
const PollView = _ref => {
let {
style,
pollSource,
openPollFlow,
theme = Theme.light,
didPressViewDetails,
didReceiveAnalyticsEvent
} = _ref;
// state
const [isLoading, setIsLoading] = React.useState(true);
const [showWebView, setShowWebView] = React.useState(false);
const [loadingTitleOverride, setLoadingTitleOverride] = React.useState(null);
const lastLoadTime = React.useRef(null);
const webViewRef = React.useRef(null);
const themeProperties = getThemeProperties(theme); // poll url
const pollUrl = React.useMemo(() => {
if (isPollSourcePollId(pollSource)) {
// found poll id, construct url
const pollId = pollSource;
return constructPollUrl({
pollId: pollId,
flow: openPollFlow // pollState?: PollState;
// themeName?: string;
// themeObject?: any;
});
} else {
// found poll url
return pollSource; // Poll Source = Poll URL
}
}, [pollSource, openPollFlow]); // handle poll url changing
React.useEffect(() => {
lastLoadTime.current = Date.now();
setIsLoading(true);
}, [pollUrl]); // manage loading states
const loadingOpacity = React.useRef(new Animated.Value(0)).current; // initial
const webViewOpacity = React.useRef(new Animated.Value(0)).current; // initial
// show/hide loading
React.useEffect(() => {
Animated.timing(loadingOpacity, {
toValue: isLoading ? 1 : 0,
duration: ANIMATION_DURATION,
useNativeDriver: true
}).start();
if (isLoading) {
setShowWebView(false);
} else {
setTimeout(() => {
setShowWebView(true);
}, ANIMATION_DURATION);
} // we do not want to run this if the animation ref changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoading]); // show/hide web view
React.useEffect(() => {
Animated.timing(webViewOpacity, {
toValue: showWebView ? 1 : 0,
duration: ANIMATION_DURATION,
useNativeDriver: true
}).start();
if (showWebView) {
setTimeout(() => {
setLoadingTitleOverride(null);
}, ANIMATION_DURATION);
} // we do not want to run this if the animation ref changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [showWebView]); // reload when foregrounding after 3m
React.useEffect(() => {
const subscription = AppState.addEventListener('change', nextAppState => {
const activeState = 'active';
const secondsSinceLastLoad = Math.round((Date.now() - (lastLoadTime.current || 0)) / 1000);
if (nextAppState === activeState && secondsSinceLastLoad > REFRESH_POLL_AGE_SECONDS) {
var _webViewRef$current;
setLoadingTitleOverride('Reloading Poll...'); // TODO: translation
setShowWebView(false);
setIsLoading(true);
lastLoadTime.current = Date.now();
(_webViewRef$current = webViewRef.current) === null || _webViewRef$current === void 0 ? void 0 : _webViewRef$current.reload();
}
});
return () => {
subscription.remove();
};
}, []); // external callbacks
const handleDidPressViewDetails = option => {
didPressViewDetails === null || didPressViewDetails === void 0 ? void 0 : didPressViewDetails(option);
};
const handleDidReceiveAnalyticsEvent = event => {
didReceiveAnalyticsEvent === null || didReceiveAnalyticsEvent === void 0 ? void 0 : didReceiveAnalyticsEvent(event);
}; // internal callbacks
const handleOnLoadEnd = () => {
setTimeout(() => {
setIsLoading(false);
}, 250);
};
const handleOnMessage = event => {
const trackInvalidMessage = () => {// console.log('❌ invalid message', event.nativeEvent.data);
}; // guards
const dataString = event.nativeEvent.data;
if (!dataString) {
trackInvalidMessage();
return;
}
const data = JSON.parse(dataString);
if (!data) {
trackInvalidMessage();
return;
}
const parseResult = EmbeddedMessage.safeParse(data);
if (!parseResult.success) {
trackInvalidMessage();
return;
}
switch (parseResult.data.event) {
case EmbeddedMessageEvent.VIEW_OPTION_DETAILS:
{
handleDidPressViewDetails(parseResult.data.payload.option);
break;
}
case EmbeddedMessageEvent.ANALYTICS_EVENT:
{
handleDidReceiveAnalyticsEvent(parseResult.data.payload);
break;
}
default:
{
break;
}
}
}; // render
const embeddedPollUrl = setPollUrlParams(pollUrl, {
embeddedState: getEmbeddedState()
});
const subdomain = getThemeFromPollUrl(embeddedPollUrl) ?? getConfig().domainConfig.subdomain;
const loadingLogoImageUrl = `https://polls-platform.s3.amazonaws.com/customer-assets/${subdomain}/mobileLoadingLogo.png`;
let loadingTitle;
if (loadingTitleOverride) {
loadingTitle = loadingTitleOverride;
} else {
switch (openPollFlow) {
case OpenPollFlow.createPoll:
{
loadingTitle = 'Creating Poll...'; // TODO: translation
break;
}
default:
case OpenPollFlow.openPoll:
{
loadingTitle = 'Loading Poll...'; // TODO: translation
break;
}
}
}
const styles = createStyles({
themeProperties
});
return /*#__PURE__*/React.createElement(View, {
style: [styles.container, style]
}, /*#__PURE__*/React.createElement(View, {
style: styles.content
}, /*#__PURE__*/React.createElement(Animated.View, {
style: { ...styles.webViewContainer,
opacity: webViewOpacity
}
}, /*#__PURE__*/React.createElement(WebView, {
style: styles.webView,
source: {
uri: embeddedPollUrl
},
ref: webViewRef,
onLoadEnd: handleOnLoadEnd,
originWhitelist: WEBVIEW_ORIGIN_WHITELIST,
onMessage: handleOnMessage
})), !showWebView && /*#__PURE__*/React.createElement(Animated.View, {
style: { ...styles.loadingContainer,
opacity: loadingOpacity
}
}, /*#__PURE__*/React.createElement(LoadingView, {
isVisible: isLoading,
title: loadingTitle,
imageUrl: loadingLogoImageUrl,
theme: theme
}))));
};
const createStyles = styleProps => {
const {
themeProperties
} = styleProps;
const {
colors: themeColors
} = themeProperties;
const styles = StyleSheet.create({
container: {
width: '100%',
height: '100%',
backgroundColor: themeColors.backgroundColor
},
content: {
width: '100%',
height: '100%',
backgroundColor: themeColors.backgroundColor
},
loadingContainer: {
position: 'absolute',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
backgroundColor: themeColors.backgroundColor
},
webViewContainer: {
width: '100%',
height: '100%'
},
webView: {
width: '100%',
height: '100%'
}
});
return styles;
};
export { PollView };
//# sourceMappingURL=index.js.map