react-native-webview#WebView TypeScript Examples

The following examples show how to use react-native-webview#WebView. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: GoogleTimeLine.tsx    From hamagen-react-native with MIT License 6 votes vote down vote up
FetchHistoryModal = ({ isVisible, isLoggedIn, webViewRef, onMessage, closeModal }: FetchHistoryModalProps) => {
  return (
    <Modal
      visible={isVisible}
      animationType="slide"
      onRequestClose={isLoggedIn ? () => { } : closeModal}
    >
      <View style={styles.container}>
        <WebviewHeader hideClose={isLoggedIn} closeModal={closeModal} />

        <WebView
          style={{ flex: 1, width: SCREEN_WIDTH }}
          ref={webViewRef}
          source={{ uri: 'https://accounts.google.com/signin/v2/identifier?service=accountsettings&flowName=GlifWebSignIn&flowEntry=ServiceLogin', }}
          startInLoadingState
          onMessage={onMessage}
          injectedJavaScript={`(function() {
            if(window.location.href.startsWith('https://myaccount.google.com/?utm_source=sign_in_no_continue')) {
                window.ReactNativeWebView.postMessage("LOGGED_IN");
            }
            })();`
          }
          originWhitelist={['*']}
        />
      </View>
    </Modal>
  );
}
Example #2
Source File: washerWeb.tsx    From THUInfo with MIT License 6 votes vote down vote up
WasherWebScreen = () => {
	const themeName = useColorScheme();
	const theme = themes(themeName);

	return (
		<View style={{backgroundColor: theme.colors.themeBackground, flex: 1}}>
			<WebView
				source={{uri: "https://washer.sdevs.top/"}}
				forceDarkOn={themeName === "dark"}
				style={{
					backgroundColor: theme.colors.themeBackground,
					color: theme.colors.text,
				}}
				setSupportMultipleWindows={false}
			/>
		</View>
	);
}
Example #3
Source File: index.tsx    From hive-keychain-mobile with MIT License 6 votes vote down vote up
render() {
    return (
      <View style={styles.container}>
        <WebView
          source={{html}}
          ref={(r) => {
            this.webref = r;
          }}
          onMessage={this.onWebViewMessage}
        />
      </View>
    );
  }
Example #4
Source File: WebView.tsx    From DoobooIAP with MIT License 6 votes vote down vote up
function Page(props: Props): ReactElement {
  const {
    route: {
      params: { uri },
    },
  } = props;

  return (
    <Container>
      <WebView source={{ uri }} />
    </Container>
  );
}
Example #5
Source File: debug.tsx    From bext with MIT License 6 votes vote down vote up
DebugScreen: FC = () => {
  const webView = useRef<WebView>(null);
  const { params } = useRoute<any>();
  const { script } = useDebug();

  return (
    <WebView
      ref={webView}
      originWhitelist={['*']}
      source={{
        uri: params.url,
      }}
      injectedJavaScriptBeforeContentLoaded={`${script.current};true;`}
    />
  );
}
Example #6
Source File: quill-editor.tsx    From react-native-cn-quill with MIT License 6 votes vote down vote up
renderWebview = (
    content: string,
    style: StyleProp<ViewStyle>,
    props: WebViewProps = {}
  ) => (
    <WebView
      scrollEnabled={false}
      hideKeyboardAccessoryView={true}
      keyboardDisplayRequiresUserAction={false}
      originWhitelist={['*']}
      style={style}
      onError={(syntheticEvent) => {
        const { nativeEvent } = syntheticEvent;
        console.warn('WebView error: ', nativeEvent);
      }}
      allowFileAccess={true}
      domStorageEnabled={false}
      automaticallyAdjustContentInsets={true}
      bounces={false}
      dataDetectorTypes="none"
      {...props}
      javaScriptEnabled={true}
      source={{ html: content }}
      ref={this._webview}
      onMessage={this.onMessage}
    />
  );
Example #7
Source File: CredentialGenerator.tsx    From jellyfin-audio-player with MIT License 6 votes vote down vote up
render() {
        const { serverUrl } = this.props;

        return (
            <WebView
                source={{ uri: serverUrl as string }}
                style={{ borderRadius: 20 }}
                onNavigationStateChange={this.handleStateChange}
                onMessage={this.handleMessage}
                ref={this.ref}
                startInLoadingState={true}
            />
        );
    }
Example #8
Source File: RecommendationList.tsx    From wuhan2020-frontend-react-native-app with MIT License 5 votes vote down vote up
function Entry(props: EntryPropsType) {
  const [visible, setVisible] = useState(false);
  const [loadingWebview, setLoading] = useState(true);

  return (
    <View>
      <ListItem
        onPress={() => setVisible(true)}
        Component={TouchableOpacity}
        title={<Text style={{ fontWeight: '800' }}>{props.title}</Text>}
        subtitle={
          <Text style={{ fontSize: 12, paddingTop: 3 }}>
            修改时间:
            {formatDate(props.modifyTime)} from {props.operator}
          </Text>
        }
        leftAvatar={{ source: { uri: props.imgUrl } }}
        rightIcon={{ name: 'unfold-more' }}
      />
      <Modal
        animationType="fade"
        presentationStyle="pageSheet"
        visible={visible}
        onDismiss={() => {
          setVisible(false);
        }}
        onRequestClose={() => {
          setVisible(false);
        }}>
        <View style={{ padding: 16, justifyContent: 'space-between' }}>
          {loadingWebview ? (
            <ActivityIndicator size="large" color="red" />
          ) : null}
          <View style={{ height: height - 150 }}>
            <WebView
              onLoad={() => setLoading(true)}
              onLoadEnd={() => setLoading(false)}
              source={{ uri: props.linkUrl }}
            />
          </View>
          <View>
            <Button
              buttonStyle={styles.button}
              title="关闭预览"
              onPress={() => {
                setVisible(false);
              }}
            />
          </View>
        </View>
      </Modal>
    </View>
  );
}
Example #9
Source File: Webview.tsx    From wuhan2020-frontend-react-native-app with MIT License 5 votes vote down vote up
function WebViewModal({
  uri,
  title,
  visible,
  onClose,
}: {
  uri: string;
  title: string;
  visible: boolean;
  onClose: () => void;
}) {
  const [loadingWebview, setLoading] = useState(true);

  return (
    <Modal
      animationType="fade"
      presentationStyle="pageSheet"
      visible={visible}
      onDismiss={onClose}
      onRequestClose={onClose}>
      <View style={{ padding: 16, justifyContent: 'space-between' }}>
        <View style={{ height: height - 150 }}>
          <H1 title={title} />
          {loadingWebview ? (
            <View style={{ paddingVertical: 20 }}>
              <Loader />
            </View>
          ) : null}
          <WebView
            onLoad={() => setLoading(true)}
            onLoadEnd={() => setLoading(false)}
            source={{ uri }}
          />
        </View>
        <View>
          <Button
            buttonStyle={styles.button}
            title="关闭预览"
            onPress={onClose}
          />
        </View>
      </View>
    </Modal>
  );
}
Example #10
Source File: login-web-view.tsx    From beancount-mobile with MIT License 5 votes vote down vote up
LoginWebView = connect(
  () => ({}),
  (dispatch) => ({
    updateReduxState(payload: {
      base: { userId: string; authToken: string };
    }): void {
      dispatch(actionUpdateReduxState(payload));
    },
  })
)(function LoginWebViewInner(props: Props): JSX.Element {
  const { updateReduxState, isSignUp } = props;
  const [progress, setProgress] = useState(0);

  const injectedJavascript = `(function() {
            window.postMessage = function(data) {
          window.ReactNativeWebView.postMessage(data);
        };
      })()`;

  return (
    <View style={{ flex: 1, flexDirection: "column" }}>
      <ProgressBar progress={progress} />
      <WebView
        injectedJavaScript={injectedJavascript}
        source={{
          uri: isSignUp ? getEndpoint("sign-up") : getEndpoint("login"),
          headers,
        }}
        style={{
          alignSelf: "stretch",
          marginTop: 0,
          height: height - statusBarHeight,
        }}
        onLoadProgress={({ nativeEvent }) => setProgress(nativeEvent.progress)}
        onMessage={async (event) => {
          try {
            const msg = decodeURIComponent(
              decodeURIComponent(event.nativeEvent.data)
            );
            const msgObj = JSON.parse(msg);
            if (msgObj.authToken) {
              const { sub } = jwtDecode(msgObj.authToken);
              analytics.identify(sub);
              await analytics.track(isSignUp ? "signed_up" : "logged_in", {});
              updateReduxState({
                base: {
                  userId: sub,
                  authToken: msgObj.authToken,
                },
              });
              props.onClose();
            }
          } catch (e) {
            // tslint:disable-next-line:no-console
            console.error(`failed to decode jwt: ${e}`);
          }
        }}
      />
    </View>
  );
})
Example #11
Source File: ledger-screen.tsx    From beancount-mobile with MIT License 5 votes vote down vote up
LedgerScreen = connect((state: AppState) => {
  return { authToken: state.base.authToken };
})(function BbsScreenInner(props: Props): JSX.Element {
  let webViewRef: WebView | null;
  const theme = useTheme().colorTheme;
  const styles = getStyles(theme);
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    async function init() {
      await analytics.track("page_view_ledger", {});
    }
    init();
  }, []);

  const onRefresh = async () => {
    await analytics.track("tap_refresh", {});
    if (webViewRef) {
      webViewRef.reload();
    }
  };

  const { authToken } = props;
  const [uri, setUri] = useState(getEndpoint("ledger/editor/"));
  return (
    <View style={styles.container}>
      <View style={{ height: statusBarHeight, backgroundColor: theme.white }} />
      <ProgressBar progress={progress} />
      <WebView
        ref={(webView) => {
          webViewRef = webView;
        }}
        onLoadProgress={({ nativeEvent }) => setProgress(nativeEvent.progress)}
        source={{
          uri,
          headers: { Authorization: `Bearer ${authToken}`, ...headers },
        }}
        onLoadStart={(navState) => {
          setUri(navState.nativeEvent.url);
        }}
      />
      <Button style={styles.refreshButton} onPress={onRefresh}>
        <Ionicons name="md-refresh" size={24} color={theme.white} />
      </Button>
    </View>
  );
})
Example #12
Source File: WebViewScene.tsx    From sellflow with MIT License 5 votes vote down vote up
export default function WebScene() {
  let {
    params: { type, webUrl },
  } = useRoute<StackRouteProp<'WebView'>>();
  let { navigate, setOptions } = useNavigation<StackNavProp<'WebView'>>();
  let { resetShoppingCart } = useResetCart();

  let title: string;

  switch (type) {
    case 'policy':
      title = t('Privacy Policy');
      break;
    case 'terms':
      title = t('Terms & Conditions');
      break;
    default:
      title = t('Payment');
  }
  useEffect(() => {
    setOptions({
      title,
    });
  });

  return webUrl ? (
    <SafeAreaView style={styles.flex}>
      <WebView
        style={styles.container}
        source={{ uri: webUrl }}
        originWhitelist={['*']}
        onShouldStartLoadWithRequest={({ url }) => {
          if (url.endsWith('thank_you')) {
            resetShoppingCart();
            navigate('OrderPlacedConfirmation', { orderNumber: '' });
            return false;
          }
          return true;
        }}
        startInLoadingState={true}
        renderLoading={() => <ActivityIndicator style={styles.center} />}
      />
    </SafeAreaView>
  ) : (
    <SafeAreaView style={styles.text}>
      <Text>{t('Please check your connection.')}</Text>
    </SafeAreaView>
  );
}
Example #13
Source File: AppMain.tsx    From tailchat with GNU General Public License v3.0 5 votes vote down vote up
AppMain: React.FC = React.memo(() => {
  return (
    <WebView
      style={styles.webview}
      source={{ uri: 'https://nightly.paw.msgbyte.com/' }}
    />
  );
})
Example #14
Source File: react-native-webview-controller.tsx    From magic-js with MIT License 5 votes vote down vote up
/**
   * Renders a React Native `<WebView>` with built-in message handling to and
   * from the Magic `<iframe>` context.
   */
  // Validating this logic requires lots of React-specific boilerplate. We will
  // revisit this method for unit testing in the future. For now, manual testing
  // is sufficient (this logic is stable right now and not expected to change in
  // the forseeable future).
  /* istanbul ignore next */
  public Relayer: React.FC = () => {
    const [show, setShow] = useState(false);

    /**
     * Saves a reference to the underlying `<WebView>` node so we can interact
     * with incoming messages.
     */
    const webViewRef = useCallback((webView: any): void => {
      this.webView = webView;
    }, []);

    /**
     * Saves a reference to the underlying `<View>` node so we can interact with
     * display styles.
     */
    const containerRef = useCallback((view: any): void => {
      this.container = {
        ...view,
        showOverlay,
        hideOverlay,
      };
    }, []);

    /**
     * Show the Magic `<WebView>` overlay.
     */
    const showOverlay = useCallback(() => {
      setShow(true);
    }, []);

    /**
     * Hide the Magic `<WebView>` overlay.
     */
    const hideOverlay = useCallback(() => {
      setShow(false);
    }, []);

    const containerStyles = useMemo(() => {
      return [this.styles['webview-container'], show ? this.styles.show : this.styles.hide];
    }, [show]);

    const handleWebViewMessage = useCallback((event: any) => {
      this.handleReactNativeWebViewMessage(event);
    }, []);

    return (
      <View ref={containerRef} style={containerStyles}>
        <WebView
          ref={webViewRef}
          source={{ uri: `${this.endpoint}/send/?params=${encodeURIComponent(this.parameters)}` }}
          onMessage={handleWebViewMessage}
          style={this.styles['magic-webview']}
        />
      </View>
    );
  };
Example #15
Source File: react-native-webview-controller.tsx    From magic-js with MIT License 5 votes vote down vote up
private webView!: WebView | null;
Example #16
Source File: CredentialGenerator.tsx    From jellyfin-audio-player with MIT License 5 votes vote down vote up
ref = createRef<WebView>();
Example #17
Source File: quill-editor.tsx    From react-native-cn-quill with MIT License 5 votes vote down vote up
private _webview: React.RefObject<WebView>;
Example #18
Source File: index.tsx    From hive-keychain-mobile with MIT License 5 votes vote down vote up
webref: WebView;
Example #19
Source File: Webview.tsx    From SQUID with MIT License 5 votes vote down vote up
WebviewScreen = () => {
  const webviewRef = useRef<WebView>()
  const uri = useNavigationParam('uri')
  const onClose = useNavigationParam('onClose')

  return (
    <SafeAreaView
      style={{
        flex: 1,
        backgroundColor: COLORS.BLACK_1,
      }}
    >
      <View
        style={{
          width: '100%',
          alignItems: 'center',
          flexDirection: 'row',
          justifyContent: 'space-between',
          paddingHorizontal: 16,
          backgroundColor: COLORS.BLACK_1,
        }}
      >
        <View style={{ flex: 1 }} />
        <CloseButton onClose={onClose} />
      </View>
      <WebView
        source={{ uri }}
        ref={ref => {
          webviewRef.current = ref
          if (webviewRef.current) {
            // setTimeout(() => {
            //   webviewRef.current.injectJavaScript(
            //     `window.ReactNativeWebView.postMessage("complete")`,
            //   )
            // }, 2000)
          }
        }}
        style={{
          flex: 1,
        }}
        onMessage={event => {
          if (event.nativeEvent.data === 'complete') {
            onClose()
          }
          // console.log('event.nativeEvent.data', event.nativeEvent.data)
          // alert(event.nativeEvent.data)
        }}
      />
    </SafeAreaView>
  )
}
Example #20
Source File: newsDetail.tsx    From THUInfo with MIT License 5 votes vote down vote up
NewsDetailScreen = ({route}: {route: NewsDetailRouteProp}) => {
	const [html, setHtml] = useState<string>("");
	const [pdf, setPdf] = useState<string>("");
	const [refreshing, setRefreshing] = useState(true);

	const themeName = useColorScheme();
	const theme = themes(themeName);
	const style = styles(themeName);

	const fetchHtml = () => {
		setRefreshing(true);
		helper
			.getNewsDetail(route.params.detail.url)
			.then(([title, res, abstract]) => {
				if (title === "PdF" && abstract === "PdF") {
					setPdf(res);
				} else {
					setHtml(`<h2>${title}</h2>${res}`);
				}
				setRefreshing(false);
			})
			.catch(() => {
				Snackbar.show({
					text: getStr("networkRetry"),
					duration: Snackbar.LENGTH_LONG,
				});
				setRefreshing(false);
			});
	};

	// eslint-disable-next-line react-hooks/exhaustive-deps
	useEffect(fetchHtml, []);

	const adaptedHtml = `<head><meta name="viewport" content="width=100, initial-scale=1"></head>
	<body>${html}</body>`;

	return (
		<>
			<View style={style.container}>
				{pdf === "" ? (
					<WebView
						source={{
							html: adaptedHtml,
							baseUrl: "https://webvpn.tsinghua.edu.cn",
						}}
						containerStyle={style.webContainer}
						userAgent={USER_AGENT}
						setSupportMultipleWindows={false}
						forceDarkOn={themeName === "dark"}
					/>
				) : (
					<Pdf
						style={style.pdf}
						source={{uri: `data:application/pdf;base64,${pdf}`}}
					/>
				)}
			</View>
			{refreshing && (
				<View style={style.container}>
					<ActivityIndicator size="large" color={theme.colors.primary} />
				</View>
			)}
		</>
	);
}
Example #21
Source File: dev.tsx    From bext with MIT License 4 votes vote down vote up
DevScreen: FC = () => {
  const [loading, setLoading] = useState(true);
  const { params } = useRoute<any>();
  const { id, modify } = params || {};
  const { data: draft, mutate } = useRequest(
    async () => {
      try {
        return await getDraft(id);
      } catch (error) {}
    },
    {
      ready: !!id,
    },
  );
  useUpdateEffect(() => {
    if (draft?.id) {
      updateUrl(draft.id, draft.url || '');
    }
  }, [draft?.url, draft?.id]);

  const navigation = useNavigation();
  useLayoutEffect(() => {
    navigation.setOptions({
      headerRight: () => (loading ? <Text>加载中...</Text> : null),
      ...(draft?.name ? { title: draft.name } : null),
    });
  }, [navigation, loading, draft?.name]);
  const [modalVisible, setModalVisible] = useState(false);
  const { script } = useDebug();
  const webView = useRef<WebView>(null);

  const onMessage = (msg: string = '{}') => {
    try {
      const data = JSON.parse(msg);
      switch (data.type) {
        case 'save':
          updateJson(id, JSON.stringify(data.payload));
          break;
        case 'ready':
          webView.current?.injectJavaScript(`
            if (window.injectDraft) {
              window.injectDraft(decodeURIComponent("${encodeURIComponent(
                draft?.json || '{}',
              )}"));
            }
            true;
          `);
          break;
        case 'debug':
          setModalVisible(true);
          script.current = data.payload;
          break;
        default:
          break;
      }
    } catch (error) {}
  };

  const navigateToDebug = () => {
    navigation.navigate(
      'debug' as never,
      {
        url: draft?.url,
      } as never,
    );
    setModalVisible(false);
  };

  return (
    <>
      <Overlay
        transparent
        isVisible={modalVisible}
        onBackdropPress={() => setModalVisible(false)}
        overlayStyle={styles.overlay}
      >
        <Input
          label="输入窗口链接"
          value={draft?.url}
          onChangeText={(url) => mutate((old) => ({ ...old, url } as any))}
        />
        <Button title="确定" disabled={!draft?.url} onPress={navigateToDebug} />
      </Overlay>
      <WebView
        ref={webView}
        originWhitelist={['*']}
        source={{
          uri: `${BEXT_ORIGIN}${
            modify
              ? '/meta?from=dev&devPath=%2Fdev%2Fscript-m'
              : '/dev/script-m'
          }`,
        }}
        onLoad={() => setLoading(false)}
        onMessage={(e) => onMessage(e.nativeEvent.data)}
      />
    </>
  );
}
Example #22
Source File: WebView.tsx    From react-native-jigsaw with MIT License 4 votes vote down vote up
NativeWebView: React.FC<WebViewProps> = ({
  source,
  style,
  optimizeVideoChat,
}) => {
  const [height, setHeight] = useState(0);

  const [cameraPermissions, setCameraPermissions] =
    useState<null | PermissionResponse>(null);

  const [microphonePermissions, setMicrophonePermissions] =
    useState<null | PermissionResponse>(null);

  const videoChatProps = optimizeVideoChat
    ? {
        allowsInlineMediaPlayback: true,
        domStorageEnabled: true,
        javaScriptEnabled: true,
        mediaCapturePermissionGrantType: "grant", // so iOS uses system settings
        mediaPlaybackRequiresUserAction: false,
        startInLoadingState: true,
      }
    : ({} as Record<string, boolean | string>);

  const onMessage = (event: WebViewMessageEvent) =>
    setHeight(Number(event.nativeEvent.data));

  const getAndSetPermissions = async (
    currentState: null | PermissionResponse,
    setCurrentState: Dispatch<SetStateAction<null | PermissionResponse>>,
    getPermission: () => Promise<PermissionResponse>,
    requestPermission: () => Promise<PermissionResponse>
  ) => {
    const currentPermission = currentState ?? (await getPermission());

    if (currentPermission.granted || !currentPermission.canAskAgain) {
      setCurrentState(currentPermission);
    } else {
      setCurrentState(await requestPermission());
    }
  };

  const getAndSetCameraAndMicrophonePermissions = async () => {
    await getAndSetPermissions(
      cameraPermissions,
      setCameraPermissions,
      Camera.getCameraPermissionsAsync,
      Camera.requestCameraPermissionsAsync
    );

    await getAndSetPermissions(
      microphonePermissions,
      setMicrophonePermissions,
      Camera.getMicrophonePermissionsAsync,
      Camera.requestMicrophonePermissionsAsync
    );
  };

  const getFinalWidth = () => {
    const { width } = Dimensions.get("window");

    if (typeof style?.width === "number") {
      return style.width;
    } else if (typeof style?.width === "string" && style.width.includes("%")) {
      return width * (Number(style.width.replace("%", "")) / 100);
    } else {
      return width;
    }
  };

  const selectComponent = () => {
    if (
      !optimizeVideoChat ||
      (cameraPermissions?.granted && microphonePermissions?.granted)
    ) {
      return (
        <WebView
          source={source}
          style={{ ...style, width: getFinalWidth() }}
          injectedJavaScript={injectFirst}
          onMessage={onMessage}
          {...videoChatProps}
        />
      );
    }

    if (
      (!cameraPermissions?.granted && cameraPermissions?.canAskAgain) ||
      (!microphonePermissions?.granted && microphonePermissions?.canAskAgain)
    ) {
      return (
        <Button
          title={"Press to enable Audio and/or Video permissions"}
          onPress={getAndSetCameraAndMicrophonePermissions}
        />
      );
    }

    if (
      (cameraPermissions?.status === "denied" &&
        cameraPermissions?.canAskAgain === false) ||
      (microphonePermissions?.status === "denied" &&
        microphonePermissions?.canAskAgain === false)
    ) {
      return (
        <Text>
          {"Set the missing Audio and/or Video permissions in System Settings"}
        </Text>
      );
    }

    return <ActivityIndicator />;
  };

  useEffect(() => {
    if (optimizeVideoChat) getAndSetCameraAndMicrophonePermissions();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [optimizeVideoChat]);

  return (
    <ScrollView
      contentContainerStyle={[
        styles.container,
        {
          height: style?.height || height,
        },
      ]}
    >
      {selectComponent()}
    </ScrollView>
  );
}
Example #23
Source File: GoogleTimeLine.tsx    From hamagen-react-native with MIT License 4 votes vote down vote up
GoogleTimeLine = ({ strings, toggleWebview, onCompletion }: GoogleTimeLineProps) => {
  const {
    general: { additionalInfo },
    locationHistory: { beforeCheckTitle, beforeCheckDesc, beforeCheckDesc2, beforeCheckButton, skip, successFoundTitle, successFoundDesc, successFoundButton, successNotFoundTitle, successNotFoundDesc, successNotFoundButton, failedTitle, failedDesc, failedButton }
  } = strings;

  const didRetry = useRef<boolean>(false);
  const webViewRef = useRef<WebView>(null);

  const [{ openWebview, isLoggedIn, state }, setState] = useState<State>({ openWebview: false, isLoggedIn: false, state: 'before' });

  const pageStateConfig = () => {
    switch (state) {
      case 'before': {
        return {
          icon: require('../../assets/locationHistory/before.png'),
          title: beforeCheckTitle,
          desc1: beforeCheckDesc,
          desc2: beforeCheckDesc2,
          button: beforeCheckButton,
          action: () => setState(prevState => ({ ...prevState, openWebview: true }))
        };
      }

      case 'successFound': {
        return {
          icon: require('../../assets/locationHistory/successFound.png'),
          title: successFoundTitle,
          desc1: successFoundDesc,
          desc2: '',
          button: successFoundButton,
          action: () => onCompletion()
        };
      }

      case 'successNotFound': {
        return {
          icon: require('../../assets/locationHistory/successNotFound.png'),
          title: successNotFoundTitle,
          desc1: successNotFoundDesc,
          desc2: '',
          button: successNotFoundButton,
          action: () => onCompletion()
        };
      }

      case 'failed': {
        return {
          icon: require('../../assets/locationHistory/failed.png'),
          title: failedTitle,
          desc1: failedDesc,
          desc2: '',
          button: failedButton,
          action: () => setState(prevState => ({ ...prevState, openWebview: true }))
        };
      }

      default: { return { icon: 0, title: '', desc1: '', desc2: '', button: '', action: () => { } }; }
    }
  };

  const retryKMLDownload = (didRetry: any, kmlUrls: string[]) => new Promise<string[]>((resolve) => {
    setTimeout(async () => {
      didRetry.current = true;
      resolve(await Promise.all(kmlUrls.map(url => fetch(url).then(r => r.text()))));
    }, IS_IOS ? 5000 : 10);
  });


  const onMessage = async ({ nativeEvent: { data } }: WebViewMessageEvent) => {
    if (!data) {
      return;
    }

    if (data === 'LOGGED_IN' && !isLoggedIn) {
      try {
        webViewRef.current?.injectJavaScript(`document.getElementsByTagName(\'html\')[0].innerHTML = \'${getLoadingHTML()}\'; true;`);

        setState(prevState => ({ ...prevState, isLoggedIn: true }));

        const kmlUrls = getLastNrDaysKmlUrls();

        let texts = await Promise.all(kmlUrls.map(url => fetch(url).then(r => r.text())));

        if (texts[0].indexOf('DOCTYPE') > -1 && texts[0].indexOf('Error') > -1) {
          if (!didRetry.current) {
            texts = await retryKMLDownload(didRetry, kmlUrls);

            if (texts[0].indexOf('DOCTYPE') > -1 && texts[0].indexOf('Error') > -1) {
              return onFetchError('Fetch KML error');
            }
          } else {
            return onFetchError('Fetch KML error');
          }
        }

        const pointsData = texts.flatMap((kml: string) => kmlToGeoJson(kml));

        if (pointsData.length === 0) {
          return onFlowEnd('successNotFound');
        }

        await insertToSampleDB(pointsData);

        return onFlowEnd('successFound');
      } catch (error) {
        await onFetchError(error);
      }
    }
  };

  const onFetchError = async (error: any) => {
    await onFlowEnd('failed');
    onError({ error });
  };

  const onFlowEnd = async (state: 'before' | 'successFound' | 'successNotFound' | 'failed') => {
    if (state !== 'failed') {
      // once 14 days flow completed for the first time
      await AsyncStorage.setItem(SHOULD_HIDE_LOCATION_HISTORY, 'true');
      store().dispatch(checkIfHideLocationHistory());
    }

    webViewRef.current?.injectJavaScript('setTimeout(() => { document.location = "https://accounts.google.com/logout"; true; }, 10)');

    setTimeout(async () => {
      didRetry.current = false;
      setState(prevState => ({ ...prevState, openWebview: false, isLoggedIn: false, state }));
      await CookieManager.clearAll(true);
    }, 300);
  };

  return (
    <View style={styles.container}>
      <View style={styles.textsContainer}>
        {
          (!IS_SMALL_SCREEN || state !== 'before') && (
            <Icon source={pageStateConfig().icon} width={154} height={64} customStyles={{ marginBottom: 50 }} />
          )
        }
        <Text style={styles.title} bold>{pageStateConfig().title}</Text>
        <Text style={{ marginBottom: 20 }}>{pageStateConfig().desc1}</Text>
        <Text bold>{pageStateConfig().desc2}</Text>
      </View>

      {
        state === 'before' && (
          <View style={{ width: SCREEN_WIDTH * 0.7, alignItems: 'center' }}>
            <TouchableOpacity onPress={() => toggleWebview(true, USAGE_PRIVACY)}>
              <Text style={{ fontSize: 14 }}>{additionalInfo}</Text>
              <View style={styles.bottomBorder} />
            </TouchableOpacity>
          </View>
        )
      }

      <View style={{ alignItems: 'center' }}>
        <ActionButton text={pageStateConfig().button} onPress={pageStateConfig().action} containerStyle={{ marginBottom: 15 }} />

        <View style={{ height: 20 }}>
          {
            (state === 'before' || state === 'failed') && (
              <TouchableOpacity onPress={onCompletion}>
                <Text style={{ fontSize: 20 }}>{skip}</Text>
              </TouchableOpacity>
            )
          }
        </View>
      </View>

      <FetchHistoryModal
        webViewRef={webViewRef}
        isVisible={openWebview}
        onMessage={onMessage}
        isLoggedIn={isLoggedIn}
        closeModal={() => setState(prevState => ({ ...prevState, openWebview: false }))}
      />
    </View>
  );
}
Example #24
Source File: IterableInboxMessageDisplay.tsx    From react-native-sdk with MIT License 4 votes vote down vote up
IterableInboxMessageDisplay = ({ 
   rowViewModel, 
   inAppContentPromise, 
   returnToInbox,
   deleteRow, 
   contentWidth,
   isPortrait
}: MessageDisplayProps) => {
   const messageTitle = rowViewModel.inAppMessage.inboxMetadata?.title
   const [inAppContent, setInAppContent] = useState<IterableHtmlInAppContent>(new IterableHtmlInAppContent(new IterableEdgeInsets(0, 0, 0, 0), ""))

   const styles = StyleSheet.create({
      messageDisplayContainer: {
         height: '100%',
         width: contentWidth, 
         backgroundColor: 'whitesmoke',
         flexDirection: 'column',
         justifyContent: 'flex-start'
      },

      header: {
         flexDirection: 'row',
         justifyContent: 'center',
         width: '100%'
      },

      returnButtonContainer: {
         flexDirection: 'row',
         justifyContent: 'flex-start',
         alignItems: 'center',
         width: '25%',
         marginLeft: 0,
         marginTop: 0
      },

      returnButton: {
         flexDirection: 'row',
         alignItems: 'center'
      },

      returnButtonIcon: {
         color: 'deepskyblue',
         fontSize: 40,
         paddingLeft: 0
      },

      returnButtonText: {
         color: 'deepskyblue',
         fontSize: 20
      },

      messageTitleContainer: {
         flexDirection: 'row',
         justifyContent: 'flex-start',
         alignItems: 'center',
         width: '75%',
         marginTop: 0
      },

      messageTitle: {
         flexDirection: 'row',
         justifyContent: 'center',
         alignItems: 'center',
         width: 0.5 * contentWidth,
      },

      messageTitleText: {
         fontWeight: 'bold',
         fontSize: 20,
         backgroundColor: 'whitesmoke'
      },
   
      contentContainer: {
         flex: 1,
      }
   })

   let {
      header,
      returnButtonContainer,
      returnButton,
      returnButtonIcon,
      returnButtonText,
      messageTitleContainer,
      messageTitleText,
      messageDisplayContainer
   } = styles

   // orientation dependent styling
   returnButtonContainer = (!isPortrait) ? { ...returnButtonContainer, marginLeft: 80 } : returnButtonContainer

   let JS = `
      const links = document.querySelectorAll('a')

      links.forEach(link => {
         link.class = link.href

         link.href = "javascript:void(0)"

         link.addEventListener("click", () => {
            window.ReactNativeWebView.postMessage(link.class)   
         })
      })
   `

   useEffect(() => {
      let mounted = true
      inAppContentPromise.then(
         (value) => {
            if(mounted) {
               setInAppContent(value)
            }
         })
      return () => {mounted = false}
   })

   function handleInAppLinkAction(event: any) {
      let URL = event.nativeEvent.data

      let action = new IterableAction("openUrl", URL, "")
      let source = IterableActionSource.inApp
      let context = new IterableActionContext(action, source)

      Iterable.trackInAppClick(rowViewModel.inAppMessage, IterableInAppLocation.inbox, URL)
      Iterable.trackInAppClose(rowViewModel.inAppMessage, IterableInAppLocation.inbox, IterableInAppCloseSource.link, URL) 

      if (URL === 'iterable://delete') { 
         returnToInbox(() => deleteRow(rowViewModel.inAppMessage.messageId))
      } else if(URL === 'iterable://dismiss') {
         returnToInbox()
      } else if (URL.slice(0, 4) === 'http') {
         returnToInbox(() => Linking.openURL(URL))
      } else {
         returnToInbox(() => {
            if(Iterable.savedConfig.urlHandler) {
               Iterable.savedConfig.urlHandler(URL, context)
            } 
         })
      }
   }

   return (
      <View style={messageDisplayContainer}>
         <View style={header}>
            <View style={returnButtonContainer}>
               <TouchableWithoutFeedback 
                  onPress={() => {
                     returnToInbox()
                     Iterable.trackInAppClose(rowViewModel.inAppMessage, IterableInAppLocation.inbox, IterableInAppCloseSource.back)
                  }}
               >
                  <View style={returnButton}>
                     <Icon name="ios-chevron-back" style={returnButtonIcon} />
                     <Text style={returnButtonText}>Inbox</Text>
                  </View>
               </TouchableWithoutFeedback>
            </View>  
            <View style={messageTitleContainer}>
               <View style={styles.messageTitle}>
                  <Text numberOfLines={1} ellipsizeMode='tail' style={messageTitleText}>{messageTitle}</Text>
               </View>
            </View>
         </View>
         <ScrollView contentContainerStyle={styles.contentContainer}>
            <WebView
               originWhiteList={['*']}
               source={{ html: inAppContent.html }}
               style={{ width: contentWidth }}
               onMessage={(event) => handleInAppLinkAction(event)}
               injectedJavaScript={JS}
            />
         </ScrollView>
      </View>
   )
}