dappros/ethora

View on GitHub
client-reactnative/src/Screens/Actions/ScanScreen.tsx

Summary

Maintainability
C
1 day
Test Coverage
import React, {useState} from 'react';
import {
  Text,
  View,
  StyleSheet,
  Platform,
  ActivityIndicator,
  TouchableOpacity,
} from 'react-native';
import QRCodeScanner from 'react-native-qrcode-scanner';
import {
  widthPercentageToDP as wp,
  heightPercentageToDP as hp,
} from 'react-native-responsive-screen';

import {useNavigation} from '@react-navigation/native';
import {launchImageLibrary} from 'react-native-image-picker';
import {PNG} from 'pngjs/browser';
import JpegDecoder from 'jpeg-js';
import jsQR from 'jsqr';
import {commonColors, textStyles} from '../../../docs/config';
import SecondaryHeader from '../../components/SecondaryHeader/SecondaryHeader';
import {showToast} from '../../components/Toast/toast';
import parseChatLink from '../../helpers/parseChatLink';
import {underscoreManipulation} from '../../helpers/underscoreLogic';
import {useStores} from '../../stores/context';
import {retrieveOtherUserVcard, subscribeToRoom} from '../../xmpp/stanzas';
import {HomeStackNavigationProp} from '../../navigation/types';
import { ImageLibraryOptions } from 'react-native-image-picker';

declare var global: any;
const Buffer = require('buffer').Buffer;
global.Buffer = Buffer; // very important

//interface and types
const options: ImageLibraryOptions = {
  mediaType: 'photo',
  includeBase64: true,
  maxHeight: 200,
  maxWidth: 200,
};
//interface and types

//handle decode data from a qr image
function createImageData(base64ImageData: any, imageType: string) {
  let decodedData: any = {};
  const bufferFrom = Buffer.from(base64ImageData, 'base64');
  if (imageType === 'image/jpeg') {
    decodedData = JpegDecoder.decode(bufferFrom, {useTArray: true});
  } else if (imageType === 'image/png') {
    decodedData = PNG.sync.read(bufferFrom);
  }
  return jsQR(
    Uint8ClampedArray.from(decodedData.data),
    decodedData.width,
    decodedData.height,
  );
}

const ScanScreen = () => {

  //mobx stores
  const {loginStore, chatStore, apiStore} = useStores();
  //mobx stores

  //local states
  const [isLoading, setIsLoading] = useState(false);
  //local states

  //local variables
  const manipulatedWalletAddress = underscoreManipulation(
    loginStore.initialData.walletAddress,
  );
  const username = loginStore.initialData.username;
  //local variables

  //navigator
  const navigation = useNavigation<HomeStackNavigationProp>();
  //navigator

  //handle to subscribe and open chat room from given QR code image
  const onSuccess = (e: any) => {
    if (!e) {
      showToast('error', 'Error', 'Invalid QR', 'top');
      setIsLoading(false);
      return;
    }
    if (e.data.includes('profileLink')) {
      const params = e.data.split('https://www.eto.li/go')[1];
      const queryParams = new URLSearchParams(params);
      const firstName: string = queryParams.get('firstName') as string;
      const lastName: string = queryParams.get('lastName') as string;
      const xmppId: string = queryParams.get('xmppId') as string;
      const walletAddressFromLink: string = queryParams.get('walletAddress') as string;

      if (loginStore.initialData.walletAddress === walletAddressFromLink) {
        navigation.navigate('ProfileScreen');
      } else {
        retrieveOtherUserVcard(
          loginStore.initialData.xmppUsername,
          xmppId,
          chatStore.xmpp,
        );

        loginStore.setOtherUserDetails({
          anotherUserFirstname: firstName,
          anotherUserLastname: lastName,
          anotherUserLastSeen: {},
          anotherUserWalletAddress: walletAddressFromLink,
        });
        navigation.navigate('OtherUserProfileScreen');
      }
    } else {

      if (e) {
        const jid = parseChatLink(e.data);

        if (jid) {
          subscribeToRoom(
            jid + apiStore.xmppDomains.CONFERENCEDOMAIN,
            manipulatedWalletAddress,
            chatStore.xmpp,
          );
          setIsLoading(false);
          navigation.navigate('ChatScreen', {
            chatJid: jid + apiStore.xmppDomains.CONFERENCEDOMAIN,
          });
        } else {
          showToast('error', 'Error', 'Invalid QR', 'top');
          setIsLoading(false);
        }
      } else {
        showToast('error', 'Error', 'Invalid QR', 'top');
        setIsLoading(false);
      }
    }
  };

  //launch image gallery
  const openGallery = () => {
    setIsLoading(true);
    launchImageLibrary(options, async (response:any) => {
      if (response.didCancel) {
        setIsLoading(false);
        console.log('User cancelled image picker');
      } else if (response.error) {
        setIsLoading(false);
        console.log('ImagePicker Error: ', response.error);
      } else if (response.customButton) {
        setIsLoading(false);
        console.log('User tapped custom button: ', response.customButton);
      } else {
        const res = createImageData(
          response.assets[0].base64,
          response.assets[0].type,
        );
        console.log(JSON.stringify(res));
        onSuccess(res);
      }
    });
  };

  return (
    <View style={styles.container}>
      <View style={{zIndex: Platform.OS === 'android' ? +1 : 0, flex: 0.2}}>
        <SecondaryHeader title="Scan" />
      </View>
      {isLoading ? (
        <ActivityIndicator size="large" color={'black'} animating={isLoading} />
      ) : (
        <QRCodeScanner
          showMarker={true}
          topViewStyle={{flex: 0}}
          containerStyle={{flex: 1}}
          cameraStyle={{
            flex: Platform.OS === 'android' ? 0.8 : 1,
            height: hp('40%'),
            width: '100%',
            justifyContent: 'flex-start',
          }}
          bottomViewStyle={{flex: 1}}
          onRead={e => onSuccess(e)}
          bottomContent={
            <TouchableOpacity
              onPress={openGallery}
              style={styles.buttonTouchable}>
              <Text style={styles.buttonTextStyle}>Upload from gallery.</Text>
            </TouchableOpacity>
          }
        />
      )}
    </View>
  );
};

export default ScanScreen;


//styles
const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  buttonTouchable: {
    fontSize: 21,
    backgroundColor: commonColors.primaryColor,
    marginTop: 32,
    borderRadius: 5,
    width: wp('53.33%'),
    justifyContent: 'center',
    alignItems: 'center',
    height: hp('6.03%'),
  },
  buttonTextStyle: {
    color: '#FFFFFF',
    fontFamily: textStyles.regularFont,
  },
});
//styles