Commit b6cd9aeb by Nguyễn Thị Thúy

Merge branch 'func_fingerprint_login' into 'func_smart_otp'

Func fingerprint login

See merge request !19
parents c5d2122a 130951cc
...@@ -57,3 +57,5 @@ buck-out/ ...@@ -57,3 +57,5 @@ buck-out/
# CocoaPods # CocoaPods
/ios/Pods/ /ios/Pods/
/android/app/release/app-release.aab
/ios/Podfile.lock
{
"version": 1,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.dcv.invest",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"properties": [],
"versionCode": 16,
"versionName": "2.0",
"enabled": true,
"outputFile": "app-release.apk"
}
]
}
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dcv.invest"> package="com.dcv.invest">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" /> <uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<application <application
android:name=".MainApplication" android:name=".MainApplication"
android:label="@string/app_name" android:allowBackup="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
>
<!-- <meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/bootsplash_background" /> -->
<activity
android:name=".MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:roundIcon="@mipmap/ic_launcher_round"
android:exported="true" android:theme="@style/AppTheme"
android:launchMode="singleTask" android:usesCleartextTraffic="true">
android:windowSoftInputMode="adjustResize"> <!-- <meta-data
<intent-filter> android:name="com.google.firebase.messaging.default_notification_color"
<action android:name="android.intent.action.VIEW"/> android:resource="@color/bootsplash_background" /> -->
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="appdcvinvest" android:host="screen" android:pathPrefix="/" <activity
/> android:name=".MainActivity"
</intent-filter> android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:exported="true"
</activity> android:label="@string/app_name"
<activity android:launchMode="singleTask"
android:name="com.zoontek.rnbootsplash.RNBootSplashActivity" android:windowSoftInputMode="adjustResize">
android:theme="@style/BootTheme" <intent-filter>
android:launchMode="singleTask"> <action android:name="android.intent.action.VIEW" />
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.BROWSABLE" />
</intent-filter> <data
android:host="screen"
android:pathPrefix="/"
android:scheme="appdcvinvest" />
</intent-filter>
</activity>
</activity>
<activity
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> android:name="com.zoontek.rnbootsplash.RNBootSplashActivity"
android:launchMode="singleTask"
android:theme="@style/BootTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application> </application>
</manifest> </manifest>
...@@ -4,6 +4,8 @@ import android.app.Application; ...@@ -4,6 +4,8 @@ import android.app.Application;
import android.content.Context; import android.content.Context;
import com.facebook.react.PackageList; import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication; import com.facebook.react.ReactApplication;
import com.rnfingerprint.FingerprintAuthPackage;
import com.rnfingerprint.FingerprintAuthPackage;
import com.learnium.RNDeviceInfo.RNDeviceInfo; import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.reactnativecommunity.netinfo.NetInfoPackage; import com.reactnativecommunity.netinfo.NetInfoPackage;
import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactInstanceManager;
......
...@@ -4,7 +4,7 @@ buildscript { ...@@ -4,7 +4,7 @@ buildscript {
ext { ext {
buildToolsVersion = "29.0.2" buildToolsVersion = "29.0.2"
minSdkVersion = 21 minSdkVersion = 21
compileSdkVersion = 28 compileSdkVersion = 29
targetSdkVersion = 29 targetSdkVersion = 29
} }
repositories { repositories {
......
rootProject.name = 'Invest' rootProject.name = 'Invest'
include ':react-native-touch-id'
project(':react-native-touch-id').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-touch-id/android')
include ':react-native-device-info' include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android') project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':@react-native-community_netinfo' include ':@react-native-community_netinfo'
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* InvestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InvestTests.m; sourceTree = "<group>"; }; 00E356F21AD99517003FC87E /* InvestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InvestTests.m; sourceTree = "<group>"; };
12715EC58B6699B513B54F09 /* Pods-Invest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Invest.debug.xcconfig"; path = "Target Support Files/Pods-Invest/Pods-Invest.debug.xcconfig"; sourceTree = "<group>"; }; 12715EC58B6699B513B54F09 /* Pods-Invest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Invest.debug.xcconfig"; path = "Target Support Files/Pods-Invest/Pods-Invest.debug.xcconfig"; sourceTree = "<group>"; };
133EF4C3267736DE00366B03 /* InvestDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = InvestDebug.entitlements; path = Invest/InvestDebug.entitlements; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* Invest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Invest.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07F961A680F5B00A75B9A /* Invest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Invest.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Invest/AppDelegate.h; sourceTree = "<group>"; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Invest/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Invest/AppDelegate.m; sourceTree = "<group>"; }; 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Invest/AppDelegate.m; sourceTree = "<group>"; };
...@@ -148,6 +149,7 @@ ...@@ -148,6 +149,7 @@
13B07FAE1A68108700A75B9A /* Invest */ = { 13B07FAE1A68108700A75B9A /* Invest */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
133EF4C3267736DE00366B03 /* InvestDebug.entitlements */,
52FB2B08262400D400DD7983 /* BootSplash.storyboard */, 52FB2B08262400D400DD7983 /* BootSplash.storyboard */,
9345F6C125FF213F006B5233 /* Fonts */, 9345F6C125FF213F006B5233 /* Fonts */,
52E1A15225F1255E00EA970D /* Invest.entitlements */, 52E1A15225F1255E00EA970D /* Invest.entitlements */,
...@@ -900,7 +902,7 @@ ...@@ -900,7 +902,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Invest/Invest.entitlements; CODE_SIGN_ENTITLEMENTS = Invest/InvestDebug.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 8; CURRENT_PROJECT_VERSION = 8;
......
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>Accect connect camera</string> <string>Accect connect camera</string>
<key>NSLocationWhenInUseUsageDescription</key> <key>NSLocationWhenInUseUsageDescription</key>
<string></string> <string/>
<key>NSPhotoLibraryUsageDescription</key> <key>NSPhotoLibraryUsageDescription</key>
<string>To upload images</string> <string>To upload images</string>
<key>UIAppFonts</key> <key>UIAppFonts</key>
...@@ -101,6 +101,8 @@ ...@@ -101,6 +101,8 @@
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>NSFaceIDUsageDescription</key> <key>NSFaceIDUsageDescription</key>
<string>Enabling Face ID allows you quick and secure access to your account.</string>
<key>NSFaceIDUsageDescription</key>
<string>Enabling Face ID allows you quick and secure access to your account.</string> <string>Enabling Face ID allows you quick and secure access to your account.</string>
</dict> </dict>
</plist> </plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)dcv.investcustomer.vn</string>
</array>
</dict>
</plist>
...@@ -91,7 +91,7 @@ target 'Invest' do ...@@ -91,7 +91,7 @@ target 'Invest' do
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info' pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
pod 'TouchID', :path => '../node_modules/react-native-touch-id'
target 'InvestTests' do target 'InvestTests' do
inherit! :complete inherit! :complete
......
...@@ -372,7 +372,7 @@ PODS: ...@@ -372,7 +372,7 @@ PODS:
- React-cxxreact (= 0.62.2) - React-cxxreact (= 0.62.2)
- React-jsi (= 0.62.2) - React-jsi (= 0.62.2)
- ReactCommon/callinvoker (= 0.62.2) - ReactCommon/callinvoker (= 0.62.2)
- RNBootSplash (3.2.0): - RNBootSplash (3.2.3):
- React-Core - React-Core
- RNCAsyncStorage (1.12.1): - RNCAsyncStorage (1.12.1):
- React-Core - React-Core
...@@ -408,6 +408,8 @@ PODS: ...@@ -408,6 +408,8 @@ PODS:
- React-Core - React-Core
- React-RCTImage - React-RCTImage
- TOCropViewController - TOCropViewController
- RNKeychain (7.0.0):
- React-Core
- RNReanimated (1.13.2): - RNReanimated (1.13.2):
- React-Core - React-Core
- RNScreens (2.18.0): - RNScreens (2.18.0):
...@@ -421,6 +423,8 @@ PODS: ...@@ -421,6 +423,8 @@ PODS:
- libwebp (~> 1.0) - libwebp (~> 1.0)
- SDWebImage/Core (~> 5.7) - SDWebImage/Core (~> 5.7)
- TOCropViewController (2.6.0) - TOCropViewController (2.6.0)
- TouchID (4.4.1):
- React
- Yoga (1.14.0) - Yoga (1.14.0)
- YogaKit (1.18.1): - YogaKit (1.18.1):
- Yoga (~> 1.14) - Yoga (~> 1.14)
...@@ -490,9 +494,11 @@ DEPENDENCIES: ...@@ -490,9 +494,11 @@ DEPENDENCIES:
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNI18n (from `../node_modules/react-native-i18n`) - RNI18n (from `../node_modules/react-native-i18n`)
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`) - RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
- RNKeychain (from `../node_modules/react-native-keychain`)
- RNReanimated (from `../node_modules/react-native-reanimated`) - RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`) - RNScreens (from `../node_modules/react-native-screens`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`) - RNVectorIcons (from `../node_modules/react-native-vector-icons`)
- TouchID (from `../node_modules/react-native-touch-id`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS: SPEC REPOS:
...@@ -611,12 +617,16 @@ EXTERNAL SOURCES: ...@@ -611,12 +617,16 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-i18n" :path: "../node_modules/react-native-i18n"
RNImageCropPicker: RNImageCropPicker:
:path: "../node_modules/react-native-image-crop-picker" :path: "../node_modules/react-native-image-crop-picker"
RNKeychain:
:path: "../node_modules/react-native-keychain"
RNReanimated: RNReanimated:
:path: "../node_modules/react-native-reanimated" :path: "../node_modules/react-native-reanimated"
RNScreens: RNScreens:
:path: "../node_modules/react-native-screens" :path: "../node_modules/react-native-screens"
RNVectorIcons: RNVectorIcons:
:path: "../node_modules/react-native-vector-icons" :path: "../node_modules/react-native-vector-icons"
TouchID:
:path: "../node_modules/react-native-touch-id"
Yoga: Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga" :path: "../node_modules/react-native/ReactCommon/yoga"
...@@ -675,7 +685,7 @@ SPEC CHECKSUMS: ...@@ -675,7 +685,7 @@ SPEC CHECKSUMS:
React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d
React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256 React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256
ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3 ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3
RNBootSplash: 24175aa28fe203b10c48dc34e78d946fd33c77af RNBootSplash: 8ef5ffa03dadd35f66510b42960ce40f397c98bf
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398 RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
RNCCheckbox: d1749e6a92178ce5dbc31e63becd1f34f0c76bbd RNCCheckbox: d1749e6a92178ce5dbc31e63becd1f34f0c76bbd
RNCClipboard: 245417a78ab585e0d4d83926c28907e7b2bc24bd RNCClipboard: 245417a78ab585e0d4d83926c28907e7b2bc24bd
...@@ -687,16 +697,18 @@ SPEC CHECKSUMS: ...@@ -687,16 +697,18 @@ SPEC CHECKSUMS:
RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211 RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211
RNI18n: e2f7e76389fcc6e84f2c8733ea89b92502351fd8 RNI18n: e2f7e76389fcc6e84f2c8733ea89b92502351fd8
RNImageCropPicker: 35a3ceb837446fa11547704709bb22b5fac6d584 RNImageCropPicker: 35a3ceb837446fa11547704709bb22b5fac6d584
RNKeychain: f75b8c8b2f17d3b2aa1f25b4a0ac5b83d947ff8f
RNReanimated: e03f7425cb7a38dcf1b644d680d1bfc91c3337ad RNReanimated: e03f7425cb7a38dcf1b644d680d1bfc91c3337ad
RNScreens: f0d7a2a440a8ba9f4574ca1ddb3368f473891be4 RNScreens: f0d7a2a440a8ba9f4574ca1ddb3368f473891be4
RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4 RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SDWebImageWebPCoder: d0dac55073088d24b2ac1b191a71a8f8d0adac21 SDWebImageWebPCoder: d0dac55073088d24b2ac1b191a71a8f8d0adac21
TOCropViewController: 3105367e808b7d3d886a74ff59bf4804e7d3ab38 TOCropViewController: 3105367e808b7d3d886a74ff59bf4804e7d3ab38
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
Yoga: 3ebccbdd559724312790e7742142d062476b698e Yoga: 3ebccbdd559724312790e7742142d062476b698e
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
YoutubePlayer-in-WKWebView: cfbf46da51d7370662a695a8f351e5fa1d3e1008 YoutubePlayer-in-WKWebView: cfbf46da51d7370662a695a8f351e5fa1d3e1008
PODFILE CHECKSUM: f6cddf7564cb78360d1490a138d2ad23d4135637 PODFILE CHECKSUM: d5f4bf13be9a761040ff8b01e612e6d56a04f1d5
COCOAPODS: 1.10.1 COCOAPODS: 1.10.1
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
"react-hook-form": "^6.15.4", "react-hook-form": "^6.15.4",
"react-native": "0.62.2", "react-native": "0.62.2",
"react-native-autocomplete-input": "^5.0.0", "react-native-autocomplete-input": "^5.0.0",
"react-native-bootsplash": "^3.2.0", "react-native-bootsplash": "^3.2.3",
"react-native-confirmation-code-field": "^6.5.1", "react-native-confirmation-code-field": "^6.5.1",
"react-native-datepicker": "^1.7.2", "react-native-datepicker": "^1.7.2",
"react-native-device-info": "^8.1.2", "react-native-device-info": "^8.1.2",
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
"react-native-i18n": "^2.0.15", "react-native-i18n": "^2.0.15",
"react-native-image-crop-picker": "^0.36.2", "react-native-image-crop-picker": "^0.36.2",
"react-native-indicators": "^0.17.0", "react-native-indicators": "^0.17.0",
"react-native-keychain": "^7.0.0",
"react-native-linear-gradient": "^2.5.6", "react-native-linear-gradient": "^2.5.6",
"react-native-modal": "^11.7.0", "react-native-modal": "^11.7.0",
"react-native-modal-dropdown": "^1.0.0", "react-native-modal-dropdown": "^1.0.0",
...@@ -49,9 +50,11 @@ ...@@ -49,9 +50,11 @@
"react-native-reanimated": "^1.13.2", "react-native-reanimated": "^1.13.2",
"react-native-safe-area-context": "^3.1.9", "react-native-safe-area-context": "^3.1.9",
"react-native-screens": "^2.17.1", "react-native-screens": "^2.17.1",
"react-native-segmented-control-tab": "^3.4.1",
"react-native-simple-radio-button": "^2.7.4", "react-native-simple-radio-button": "^2.7.4",
"react-native-swiper": "^1.6.0", "react-native-swiper": "^1.6.0",
"react-native-tab-view": "^2.15.2", "react-native-tab-view": "^2.15.2",
"react-native-touch-id": "^4.4.1",
"react-native-vector-icons": "^8.0.0", "react-native-vector-icons": "^8.0.0",
"react-native-webview": "^11.2.5", "react-native-webview": "^11.2.5",
"react-native-youtube": "^2.0.1", "react-native-youtube": "^2.0.1",
......
...@@ -17,6 +17,7 @@ import R from '../assets/R'; ...@@ -17,6 +17,7 @@ import R from '../assets/R';
import {isTablet} from 'react-native-device-info'; import {isTablet} from 'react-native-device-info';
import {RSA_KEY, MY_RSA_KEY} from './constants'; import {RSA_KEY, MY_RSA_KEY} from './constants';
import JSEncrypt from 'jsencrypt'; import JSEncrypt from 'jsencrypt';
import KEY from '../assets/AsynStorage';
export const encryptRSAString = (val) => { export const encryptRSAString = (val) => {
var encrypt = new JSEncrypt(); var encrypt = new JSEncrypt();
...@@ -33,7 +34,7 @@ export const decryptRSAString = (val) => { ...@@ -33,7 +34,7 @@ export const decryptRSAString = (val) => {
}; };
export const logout = (navigation) => { export const logout = (navigation) => {
AsyncStorage.clear(); AsyncStorage.multiRemove([KEY.ACCOUNT, KEY.FIREBASE, KEY.TOKEN])
navigation.reset({ navigation.reset({
index: 1, index: 1,
routes: [{name: AUTHEN}], routes: [{name: AUTHEN}],
......
import React, {useState, useEffect} from 'react'; import React, {useState, useEffect} from 'react';
import { import {
View, View,
Text, Text,
StyleSheet, StyleSheet,
Image, Image,
TouchableOpacity, TouchableOpacity,
KeyboardAvoidingView, KeyboardAvoidingView,
Platform, Platform,
Alert, Alert,
} from 'react-native'; } from 'react-native';
import InputIcon from '../../components/Input/InputIcon'; import InputIcon from '../../components/Input/InputIcon';
import {getFontXD, HEIGHTXD, WIDTHXD} from '../../Config/Functions'; import {getFontXD, HEIGHTXD, WIDTHXD} from '../../Config/Functions';
import R from '../../assets/R'; import R from '../../assets/R';
import {useNavigation} from '@react-navigation/native'; import {useNavigation} from '@react-navigation/native';
import { import {
TABNAVIGATOR, TABNAVIGATOR,
FORGOTPASSWORD, FORGOTPASSWORD,
CONFIRMEMAIL, CONFIRMEMAIL,
} from '../../routers/ScreenNames'; } from '../../routers/ScreenNames';
import {checkFormatArray, encryptRSAString} from '../../Config/Functions'; import {checkFormatArray, encryptRSAString} from '../../Config/Functions';
import {loginApi} from '../../apis/Functions/users'; import {loginApi} from '../../apis/Functions/users';
...@@ -29,185 +29,258 @@ import messaging from '@react-native-firebase/messaging'; ...@@ -29,185 +29,258 @@ import messaging from '@react-native-firebase/messaging';
import I18n from '../../helper/i18/i18n'; import I18n from '../../helper/i18/i18n';
import AppText from '../../components/AppText'; import AppText from '../../components/AppText';
import {showAlert, TYPE} from '../../components/DropdownAlert'; import {showAlert, TYPE} from '../../components/DropdownAlert';
import TouchID from 'react-native-touch-id';
import {call} from 'redux-saga/effects';
import KeychainService from '../../services/keychainService';
import * as Keychain from 'react-native-keychain';
import EntypoIcon from 'react-native-vector-icons/Entypo';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
const Login = (props) => { const Login = (props) => {
const {navigation} = props; const {navigation} = props;
const [email, setEmail] = useState(''); const [email, setEmail] = useState('');
const [pass, setPass] = useState(''); const [pass, setPass] = useState('');
const [biometryType, setBiometryType] = useState(null);
const [isShowBiometryLogin, setIsShowBiometryLogin] = useState(false);
const navigate = useNavigation(); const navigate = useNavigation();
const optionalConfigObject = {
title: 'Authentication Required', // Android
color: '#e00606', // Android,
fallbackLabel: '', // iOS (if empty, then label is hidden)
};
const getTokenDevice = async () => {
let fcmToken = await AsyncStorage.getItem(KEY.FIREBASE);
const getTokenDevice = async () => { if (!fcmToken) {
let fcmToken = await AsyncStorage.getItem(KEY.FIREBASE); fcmToken = await messaging().getToken();
if (fcmToken) {
if (!fcmToken) { AsyncStorage.setItem(KEY.FIREBASE, fcmToken);
fcmToken = await messaging().getToken(); }
if (fcmToken) { }
AsyncStorage.setItem(KEY.FIREBASE, fcmToken); };
} const getLoginByBiometry = async () => {
} let loginByBiometry = await AsyncStorage.getItem(KEY.IS_LOGIN_BY_BIOMETRY);
}; if (loginByBiometry) {
loginByBiometry = JSON.parse(loginByBiometry)
useEffect(() => { setIsShowBiometryLogin(loginByBiometry.isLoginByBiometry);
props.hideLoading(); loginByBiometry.isLoginByBiometry && Keychain.getSupportedBiometryType({}).then((biometryType) => {
getAccount(); setBiometryType(biometryType);
getTokenDevice(); });
}, []); }
};
useEffect(() => {
props.hideLoading();
getAccount();
getTokenDevice();
getLoginByBiometry();
}, []);
const getAccount = async () => { const getAccount = async () => {
const jsonValue = await AsyncStorage.getItem(KEY.ACCOUNT); const jsonValue = await AsyncStorage.getItem(KEY.ACCOUNT);
const account = JSON.parse(jsonValue); const account = JSON.parse(jsonValue);
if (account) { if (account) {
onSubmitLogin(account.email, account.pass); onSubmitLogin(account.email, account.pass);
} }
}; };
const getCredentialInfo = async () => {
try {
// Retrieve the credentials
const options = {
authenticationPrompt: {
title: 'Authentication needed',
cancel: 'Cancel',
},
};
const credentials = await Keychain.getGenericPassword(options);
if (credentials) {
console.log(
'Credentials successfully loaded for user ', credentials,
);
onSubmitLogin(credentials.username, credentials.password);
const onSubmitLogin = async (email, pass) => { } else {
const titles = [ showAlert(
I18n.t('Username').toLowerCase(), TYPE.ERROR,
I18n.t('Password').toLowerCase(), I18n.t('Notification'),
]; I18n.t('HaveNotCredential', {type: biometryType == 'FaceID' ? I18n.t('FaceId') : I18n.t('Fingerprint')}),
const index = checkFormatArray([email, pass]); );
console.log('No credentials stored');
}
} catch (error) {
console.log('Keychain couldn\'t be accessed!', error);
}
};
const onSubmitLogin = async (email, pass) => {
const titles = [
I18n.t('Username').toLowerCase(),
I18n.t('Password').toLowerCase(),
];
const index = checkFormatArray([email, pass]);
if (index === true) { if (index === true) {
firebase = await AsyncStorage.getItem(KEY.FIREBASE); firebase = await AsyncStorage.getItem(KEY.FIREBASE);
props.showLoading(); props.showLoading();
const res = await loginApi({ const res = await loginApi({
email, email,
password: encryptRSAString(pass), password: encryptRSAString(pass),
platform: Platform.OS, platform: Platform.OS,
device_token: firebase, device_token: firebase,
account_type: 'CUSTOMER', account_type: 'CUSTOMER',
}); });
props.hideLoading(); props.hideLoading();
if (res.data) { if (res.data) {
if (res.data.code == 200 && res.data.data) { if (res.data.code == 200 && res.data.data) {
const jsonValue = JSON.stringify({email, pass}); const jsonValue = JSON.stringify({email, pass});
AsyncStorage.setItem(KEY.TOKEN, res.data.data.token); AsyncStorage.setItem(KEY.TOKEN, res.data.data.token);
AsyncStorage.setItem(KEY.ACCOUNT, jsonValue); AsyncStorage.setItem(KEY.ACCOUNT, jsonValue);
props.saveUserToRedux(res.data.data); props.saveUserToRedux(res.data.data);
navigate.reset({ navigate.reset({
index: 1, index: 1,
routes: [{name: TABNAVIGATOR}], routes: [{name: TABNAVIGATOR}],
}); });
} else {
showAlert(TYPE.ERROR, I18n.t('Notification'), res.data.message);
}
} else {
showAlert(
TYPE.ERROR,
I18n.t('Notification'),
I18n.t('Systemmaintenance'),
);
}
} else { } else {
showAlert(TYPE.ERROR, I18n.t('Notification'), res.data.message); showAlert(
TYPE.WARN,
I18n.t('Notification'),
I18n.t('Please_fill_in') + titles[index],
);
} }
} else { };
showAlert(
TYPE.ERROR, return (
I18n.t('Notification'), <View
I18n.t('Systemmaintenance'), style={{
); flex: 1,
} paddingHorizontal: 20,
} else { paddingTop: 20,
showAlert( backgroundColor: 'white',
TYPE.WARN, }}>
I18n.t('Notification'), <InputIcon
I18n.t('Please_fill_in') + titles[index], icon={R.images.iconUser3}
); title={'Email'}
} onChangeText={(val) => setEmail(val)}
}; value={email}
/>
<InputIcon
icon={R.images.iconLock}
title={'Password'}
isPassWord={true}
onChangeText={(val) => setPass(val)}
value={pass}
/>
<TouchableOpacity
onPress={() => navigate.navigate(CONFIRMEMAIL)}
style={styles.forgotView}>
<AppText i18nKey={'ForgotPassword'} style={styles.txtTitle}/>
</TouchableOpacity>
return ( <View
<View style={{
style={{ marginVertical: 20,
flex: 1, alignItems: 'center',
paddingHorizontal: 20, }}>
paddingTop: 20, <TouchableOpacity
backgroundColor: 'white', onPress={() => onSubmitLogin(email, pass)}
}}> style={styles.wrapLogin}>
<InputIcon <AppText i18nKey={'Login'} style={styles.txtLogin}/>
icon={R.images.iconUser3} <Image source={R.images.iconRight1} style={styles.imgIcon}/>
title={'Email'} </TouchableOpacity>
onChangeText={(val) => setEmail(val)} {isShowBiometryLogin ?
value={email} <View style={{flexDirection: 'row', marginTop: WIDTHXD(70)}}>
/> {biometryType == 'FaceID' ?
<InputIcon <TouchableOpacity
icon={R.images.iconLock} onPress={() => {
title={'Password'} getCredentialInfo();
isPassWord={true} }}>
onChangeText={(val) => setPass(val)} <Image source={R.images.iconFaceId} style={[styles.imgIconBiometry, {tintColor: R.colors.main}]}/>
value={pass} </TouchableOpacity>
/> :
<TouchableOpacity <TouchableOpacity
onPress={() => navigate.navigate(CONFIRMEMAIL)} onPress={() => {
style={styles.forgotView}> getCredentialInfo();
<AppText i18nKey={'ForgotPassword'} style={styles.txtTitle} /> }}>
</TouchableOpacity> <Image source={R.images.fingerprint} style={styles.imgIconBiometry}/>
</TouchableOpacity>
<View }
style={{ </View>
marginVertical: 20, : null}
alignItems: 'center',
}}>
<TouchableOpacity
onPress={() => onSubmitLogin(email, pass)}
style={styles.wrapLogin}>
<AppText i18nKey={'Login'} style={styles.txtLogin} />
<Image source={R.images.iconRight1} style={styles.imgIcon} />
</TouchableOpacity>
<View style={styles.row}> <View style={styles.row}>
<AppText i18nKey={'Have_account'} style={styles.txtTitle} /> <AppText i18nKey={'Have_account'} style={styles.txtTitle}/>
<TouchableOpacity <TouchableOpacity
onPress={() => { onPress={() => {
navigation.navigate('REGISTOR'); navigation.navigate('REGISTOR');
}}> }}>
<AppText i18nKey={'Register'} style={styles.txtRegistor} /> <AppText i18nKey={'Register'} style={styles.txtRegistor}/>
</TouchableOpacity> </TouchableOpacity>
</View>
</View>
<View style={{height: 100}}/>
</View> </View>
</View> );
<View style={{height: 100}} />
</View>
);
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
forgotView: { forgotView: {
marginVertical: 20, marginVertical: 20,
alignItems: 'flex-end', alignItems: 'flex-end',
}, },
txtTitle: { txtTitle: {
fontSize: getFontXD(42), fontSize: getFontXD(42),
color: '#929292', color: '#929292',
}, },
txtLogin: { txtLogin: {
fontSize: getFontXD(48), fontSize: getFontXD(48),
color: 'white', color: 'white',
fontWeight: '700', fontWeight: '700',
}, },
wrapLogin: { wrapLogin: {
width: WIDTHXD(512), width: WIDTHXD(512),
height: HEIGHTXD(150), height: HEIGHTXD(150),
backgroundColor: '#1C6AF6', backgroundColor: '#1C6AF6',
borderRadius: 30, borderRadius: 30,
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
}, },
imgIcon: { imgIcon: {
width: WIDTHXD(72), width: WIDTHXD(72),
height: HEIGHTXD(72), height: HEIGHTXD(72),
marginLeft: 5, marginLeft: 5,
}, },
row: { imgIconBiometry: {
flexDirection: 'row', width: WIDTHXD(120),
marginTop: 30, height: WIDTHXD(120),
}, },
txtRegistor: { row: {
marginLeft: WIDTHXD(10), flexDirection: 'row',
fontSize: getFontXD(42), marginTop: 30,
color: '#1473E6', },
}, txtRegistor: {
marginLeft: WIDTHXD(10),
fontSize: getFontXD(42),
color: '#1473E6',
},
}); });
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return {}; return {};
}; };
export default connect(mapStateToProps, { export default connect(mapStateToProps, {
showLoading, showLoading,
hideLoading, hideLoading,
saveUserToRedux, saveUserToRedux,
})(Login); })(Login);
import React, {useState, useEffect, useRef} from 'react';
import {Modal, View, TouchableWithoutFeedback, TouchableOpacity, StyleSheet, Text, TextInput} from 'react-native';
import IconClose from 'react-native-vector-icons/AntDesign';
import R from '../../assets/R';
import {WIDTHXD, getWidth, HEIGHTXD, getFontXD, getHeight} from '../../Config/Functions';
import {showAlert, TYPE} from '../../components/DropdownAlert';
import I18n from '../../helper/i18/i18n';
import DropdownAlert from 'react-native-dropdownalert';
const EnterPasswordModal = (props) => {
const [visible, setVisible] = useState(true);
const [pass, setPass] = useState('');
const dropDownAlertRef = useRef(null);
const onChangeText = (text) => {
setPass(text);
};
useEffect(() => {
setVisible(props.visible);
}, [props.visible]);
return <Modal
animationType='slide'
transparent={true}
visible={visible}
onRequestClose={() => {
props.setVisible(false);
setPass('');
}}
>
<TouchableWithoutFeedback
onPress={() => {
setPass('');
props.setVisible(false);
}}
>
<View
style={styles.opacity}
>
<View style={styles.modal}>
<View style={styles.viewTitle}>
<View style={styles.viewEmpty}></View>
<Text style={styles.titlePopup}>{I18n.t('EnterPassword')}</Text>
<TouchableOpacity onPress={() => {
setPass('');
props.setVisible(false);
}} style={styles.btClose}>
<IconClose name='close' size={WIDTHXD(48)} color={R.colors.black}/>
</TouchableOpacity>
</View>
<TextInput
autoCapitalize="none"
onChangeText={(val) => onChangeText(val)}
style={styles.txtInput}
placeholderTextColor={R.colors.placeHolder}
secureTextEntry={true}
autoFocus={true}
value={pass}
/>
<TouchableOpacity onPress={() => {
if (pass == '') {
dropDownAlertRef.current.alertWithType(TYPE.WARN, I18n.t('Notification'), `${I18n.t('Please_fill_in')}${I18n.t('Password')}`);
} else {
props.accept(pass);
setPass('')
}
}}>
<Text style={styles.txtAccept}>{I18n.t('Ok')}</Text>
</TouchableOpacity>
</View>
<DropdownAlert
inactiveStatusBarBackgroundColor={R.colors.main}
activeStatusBarBackgroundColor={R.colors.main}
warnImageSrc={R.images.iconWarn}
successImageSrc={R.images.iconSuccess}
errorImageSrc={R.images.iconError}
titleStyle={{color: '#fff'}}
messageStyle={{color: '#fff'}}
updateStatusBar={false}
closeInterval={1000}
ref={dropDownAlertRef}
warnColor={R.colors.orange400}
defaultContainer={{
borderBottomRightRadius: WIDTHXD(30),
borderBottomLeftRadius: WIDTHXD(30),
paddingTop: HEIGHTXD(30),
paddingVertical: HEIGHTXD(30),
paddingHorizontal: WIDTHXD(20),
}}
/>
</View>
</TouchableWithoutFeedback>
</Modal>;
};
const styles = StyleSheet.create({
opacity: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#rgba(0,0,0,0.7)',
},
titlePopup: {
fontSize: getFontXD(48),
color: R.colors.black,
textAlign: 'center',
flex: 10,
},
viewEmpty: {
flex: 1,
},
viewTitle: {
flexDirection: 'row',
width: WIDTHXD(960),
borderBottomWidth: 0.3,
paddingBottom: HEIGHTXD(50),
borderBottomColor: R.colors.iconGray,
borderColor: R.colors.iconGray,
},
txtAccept: {
fontSize: getFontXD(48),
color: R.colors.main,
textAlign: 'center',
marginTop: HEIGHTXD(50),
},
btClose: {
flex: 1,
justifyContent: 'center',
alignItems: 'flex-start',
},
modal: {
backgroundColor: R.colors.white,
width: WIDTHXD(960),
justifyContent: 'center',
// maxHeight: HEIGHTXD(1300),
borderRadius: WIDTHXD(20),
paddingBottom: WIDTHXD(40),
// minHeight: HEIGHTXD(369),
paddingVertical: HEIGHTXD(59),
paddingTop: HEIGHTXD(61),
paddingHorizontal: WIDTHXD(60),
alignItems: 'center',
},
txtInput: {
width: WIDTHXD(880),
height: HEIGHTXD(109),
marginTop: HEIGHTXD(50),
color: 'black',
borderRadius: 7,
borderWidth: 0.7,
borderColor: '#DBDBDB',
fontSize: getFontXD(42),
paddingVertical: 5,
paddingHorizontal: 10,
backgroundColor: 'white',
shadowColor: '#AFA9A9',
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.25,
shadowRadius: 1.84,
elevation: 1,
},
});
export default EnterPasswordModal;
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import {View, Text, Switch, StyleSheet} from 'react-native'; import {View, Text, Switch, StyleSheet, Platform} from 'react-native';
import HeaderBack from '../../components/Header/HeaderBack'; import HeaderBack from '../../components/Header/HeaderBack';
import {getFontXD} from '../../Config/Functions'; import {encryptRSAString, getFontXD} from '../../Config/Functions';
import PickerItem from '../../components/Picker/PickerItem'; import PickerItem from '../../components/Picker/PickerItem';
import AppText from '../../components/AppText'; import AppText from '../../components/AppText';
import {changeLanguage} from '../../actions/language'; import {changeLanguage} from '../../actions/language';
...@@ -9,86 +9,146 @@ import {connect} from 'react-redux'; ...@@ -9,86 +9,146 @@ import {connect} from 'react-redux';
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
import KEY from '../../assets/AsynStorage'; import KEY from '../../assets/AsynStorage';
import I18n, {setLocation} from '../../helper/i18/i18n'; import I18n, {setLocation} from '../../helper/i18/i18n';
import EnterPasswordModal from './EnterPasswordModal';
import * as Keychain from 'react-native-keychain';
import {showLoading, hideLoading} from '../../actions/loadingAction';
import {verifyPassword} from '../../apis/Functions/users';
import {showAlert, TYPE} from '../../components/DropdownAlert';
const dataLanguage = [ const dataLanguage = [
{ {
value: 'vi', value: 'vi',
name: 'Vietnamese', name: 'Vietnamese',
}, },
{ {
value: 'en', value: 'en',
name: 'English', name: 'English',
}, },
]; ];
const SettingView = (props) => { const SettingView = (props) => {
const [isEnabled, setIsEnabled] = useState(true); const [isEnabled, setIsEnabled] = useState(false);
const toggleSwitch = () => setIsEnabled((previousState) => !previousState); const [visible, setVisible] = useState(false);
const [biometryType, setBiometryType] = useState(null);
const toggleSwitch = async () => {
if (isEnabled == true) {
await Keychain.resetGenericPassword();
AsyncStorage.setItem(KEY.IS_LOGIN_BY_BIOMETRY, JSON.stringify({isLoginByBiometry : false}));
setIsEnabled(false);
} else {
setVisible(true);
}
};
const [language, setLanguage] = useState();
useEffect(() => {
convertLanguage();
getLoginByBiometry()
Keychain.getSupportedBiometryType({}).then((biometryType) => {
setBiometryType(biometryType);
});
}, []);
const getLoginByBiometry = async () => {
let loginByBiometry = await AsyncStorage.getItem(KEY.IS_LOGIN_BY_BIOMETRY);
if (loginByBiometry) {
setIsEnabled(JSON.parse(loginByBiometry).isLoginByBiometry);
}
};
const [language, setLanguage] = useState(); const savePass = async (pass) => {
setVisible(false);
props.showLoading();
console.log(props.user);
const res = await verifyPassword({
password: encryptRSAString(pass),
platform: Platform.OS,
account_type: 'CUSTOMER',
});
if (res.status == 200 && res.data) {
if (res.data.code == 200) {
await Keychain.setGenericPassword(props.user.email, pass, {
accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET,
});
AsyncStorage.setItem(KEY.IS_LOGIN_BY_BIOMETRY, JSON.stringify({isLoginByBiometry : true}));
setIsEnabled(true);
} else {
showAlert(TYPE.ERROR, I18n.t('Notification'), res.data.message);
}
} else {
showAlert(TYPE.ERROR, I18n.t('Notification'), I18n.t('HaveIssue'));
}
props.hideLoading();
};
useEffect(() => { const convertLanguage = () => {
convertLanguage(); const temp = dataLanguage.filter((e) => e.value == props.language.language);
}, []); setLanguage(temp[0].name);
};
const convertLanguage = () => { return (
const temp = dataLanguage.filter((e) => e.value == props.language.language); <>
setLanguage(temp[0].name); <View style={{flex: 1}}>
}; <HeaderBack title={'Setting'}/>
<View style={{flex: 1, padding: 10}}>
<View style={styles.row}>
<AppText i18nKey={'Language'} style={styles.txtTitle}/>
<PickerItem
width={200}
defaultValue={language}
value={language}
data={dataLanguage}
onValueChange={(value, items) => {
setLanguage(items.name);
props.changeLanguage(items.value);
AsyncStorage.setItem(KEY.LANGUAGE, items.value);
setLocation(I18n, items.value);
props.updateLangue(items.value);
}}
/>
</View>
<View style={styles.row}>
<Text style={styles.txtTitle}>{I18n.t('LoginBy', {type: biometryType =='FaceID' ? I18n.t('FaceId') : I18n.t('Fingerprint')})}</Text>
<Switch
trackColor={{false: '#DBDBDB', true: '#1C6AF6'}}
ios_backgroundColor="#767577"
thumbColor={'#f4f3f4'}
onValueChange={toggleSwitch}
value={isEnabled}
/>
</View>
return ( </View>
<View style={{flex: 1}}> <EnterPasswordModal
<HeaderBack title={'Setting'} /> visible={visible}
<View style={{flex: 1, padding: 10}}> accept={(pass) => savePass(pass)}
{/* <View style={styles.row}> setVisible={(visible) => setVisible(visible)}
<Text style={styles.txtTitle}>Bật thông báo</Text> />
<Switch
trackColor={{false: '#DBDBDB', true: '#1C6AF6'}}
ios_backgroundColor="#767577"
thumbColor={'#f4f3f4'}
onValueChange={toggleSwitch}
value={isEnabled}
/>
</View> */}
<View style={styles.row}> </View>
<AppText i18nKey={'Language'} style={styles.txtTitle} /> </>
<PickerItem );
width={200}
defaultValue={language}
value={language}
data={dataLanguage}
onValueChange={(value, items) => {
setLanguage(items.name);
props.changeLanguage(items.value);
AsyncStorage.setItem(KEY.LANGUAGE, items.value);
setLocation(I18n, items.value);
props.updateLangue(items.value);
}}
/>
</View>
</View>
</View>
);
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
txtTitle: { txtTitle: {
fontSize: getFontXD(46), fontSize: getFontXD(46),
color: '#001C51', color: '#001C51',
}, },
row: { row: {
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-between', justifyContent: 'space-between',
alignItems: 'center', alignItems: 'center',
marginBottom: 20, marginBottom: 20,
}, },
}); });
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
language: state.languageReducer, user: state.userReducer,
}; language: state.languageReducer,
};
}; };
export default connect(mapStateToProps, {changeLanguage})(SettingView); export default connect(mapStateToProps, {changeLanguage, showLoading, hideLoading})(SettingView);
...@@ -91,3 +91,8 @@ export const updateOTPApiSmart = async (body) => ...@@ -91,3 +91,8 @@ export const updateOTPApiSmart = async (body) =>
PostData(url.urlUpdateSmartOTP, body) PostData(url.urlUpdateSmartOTP, body)
.then((res) => res) .then((res) => res)
.catch((err) => err); .catch((err) => err);
export const verifyPassword = async (body) =>
PostData(url.urlVerifyPassword, body)
.then((res) => res)
.catch((err) => err);
...@@ -68,4 +68,5 @@ export default { ...@@ -68,4 +68,5 @@ export default {
urlGetSmartOTP: root + 'api/v2/customer-get-otp', urlGetSmartOTP: root + 'api/v2/customer-get-otp',
urlStoreOTPSmart: root + 'api/v1/customers/store-otp-password', urlStoreOTPSmart: root + 'api/v1/customers/store-otp-password',
urlVerufySmartOTP: root + 'api/v1/customers/verify-otp-password', urlVerufySmartOTP: root + 'api/v1/customers/verify-otp-password',
urlVerifyPassword: `${root}api/auth/customer-verify-password`,
}; };
...@@ -3,6 +3,7 @@ const KEY = { ...@@ -3,6 +3,7 @@ const KEY = {
FIREBASE: '@Firebase', FIREBASE: '@Firebase',
ACCOUNT: '@ACCOUNT', ACCOUNT: '@ACCOUNT',
LANGUAGE: '@LANGUAGE', LANGUAGE: '@LANGUAGE',
IS_LOGIN_BY_BIOMETRY: '@IS_LOGIN_BY_BIOMETRY',
}; };
export default KEY; export default KEY;
...@@ -118,6 +118,8 @@ const images = { ...@@ -118,6 +118,8 @@ const images = {
rules: require('./images/rules.png'), rules: require('./images/rules.png'),
changeSmart: require('./images/changeSmart.png'), changeSmart: require('./images/changeSmart.png'),
faq: require('./images/faq.png'), faq: require('./images/faq.png'),
fingerprint: require('./images/fingerprint.png'),
iconFaceId: require('./images/iconFaceID.png'),
}; };
export default images; export default images;
...@@ -156,13 +156,13 @@ export default { ...@@ -156,13 +156,13 @@ export default {
ChangePasswordSuccess: 'Change password success', ChangePasswordSuccess: 'Change password success',
EnterAllInfo: 'Please complete all information ', EnterAllInfo: 'Please complete all information ',
Date: 'Date', Date: 'Date',
ReviewService: 'Review service of DCV Invest', ReviewService: 'Review services of DCV Invest',
VeryBad: 'Very bad', VeryBad: 'Very bad',
Bad: 'Bad', Bad: 'Bad',
Normal: 'Normal', Normal: 'Normal',
Good: 'Good', Good: 'Good',
VeryGood: 'Very good', VeryGood: 'Very good',
ShareYourFeel: 'Share your feel about service', ShareYourFeel: 'Share your feel about services',
UploadImage: 'Upload image', UploadImage: 'Upload image',
BonusMoney: 'Bonus money', BonusMoney: 'Bonus money',
Content: 'Content', Content: 'Content',
...@@ -328,4 +328,10 @@ export default { ...@@ -328,4 +328,10 @@ export default {
WarnMaxReqestWithdraw: 'Invalid withdrawal amount', WarnMaxReqestWithdraw: 'Invalid withdrawal amount',
YouHaveNotSettingSmartOTP: 'You have not installed Smart OTP', YouHaveNotSettingSmartOTP: 'You have not installed Smart OTP',
OTP: 'Enter OTP', OTP: 'Enter OTP',
HaveIssue: 'Have an issue, try again!',
HaveNotCredential: 'Can not login by %{type}, please return on login by %{type}',
LoginBy: 'Login by %{type}',
Fingerprint: 'Fingerprint',
FaceId: 'FaceId'
}; };
...@@ -325,4 +325,9 @@ export default { ...@@ -325,4 +325,9 @@ export default {
ForgotSmartOTP: 'Quên Smart OTP', ForgotSmartOTP: 'Quên Smart OTP',
YouHaveNotSettingSmartOTP: 'Bạn chưa cài đặt Smart OTP', YouHaveNotSettingSmartOTP: 'Bạn chưa cài đặt Smart OTP',
OTP: 'Nhập OTP', OTP: 'Nhập OTP',
HaveIssue: 'Có lỗi xảy ra, vui lòng thử lại',
HaveNotCredential: 'Không thể đăng nhập được bằng %{type}, vui lòng bật lại chức năng đăng nhập bằng %{type}',
LoginBy: 'Đăng nhập bằng %{type}',
Fingerprint: 'vân tay',
FaceId: 'nhận diện khuôn mặt'
}; };
import TouchID from 'react-native-touch-id';
import {Platform} from 'react-native'
export const checkBiometricSupportednEnrolled = async () => {
const optionalConfigObject = {
unifiedErrors: false, // use unified error messages (default false)
passcodeFallback: false // if true is passed, it will allow isSupported to return an error if the device is not enrolled in touch id/face id etc. Otherwise, it will just tell you what method is supported, even if the user is not enrolled. (default false)
}
return new Promise((resolve, reject) => {
//isSupported returns both cases 1. if supported 2. Is enabled/configured/enrolled
TouchID.isSupported(optionalConfigObject)
.then(biometryType => {
// Success code.
// as we are focusing on fingerprint for now
if (biometryType && biometryType != 'FaceID') {
resolve(true);
} else {
let fingerprintLableForOS = Platform.OS == "ios" ? "Touch ID" : "Fingerprint";
reject( fingerprintLableForOS + " is not available on this device");
}
})
.catch(error => {
// iOS Error Format and android error formats are different
// android use code and ios use name
// check at https://github.com/naoufal/react-native-touch-id
let errorCode = Platform.OS == "ios" ? error.name : error.code;
if (errorCode === "LAErrorTouchIDNotEnrolled" || errorCode === "NOT_AVAILABLE" || errorCode === "NOT_ENROLLED") {
let fingerprintLableForOS = Platform.OS == "ios" ? "Touch ID" : "Fingerprint";
resolve(fingerprintLableForOS + " has no enrolled fingers. Please go to settings and enable " + fingerprintLableForOS + " on this device.");
} else {
reject(Platform.OS == "ios" ? error.message : translations.t(error.code));
}
});
});
}
export const authenticateFingerPrint = () => {
return new Promise((resolve, reject) => {
// configuration object for more detailed dialog setup and style:
// const optionalConfigObject = {
// title: 'Authentication Required', // Android
// imageColor: '#e00606', // Android
// imageErrorColor: '#ff0000', // Android
// sensorDescription: 'Touch sensor', // Android
// sensorErrorDescription: 'Failed', // Android
// cancelText: 'Cancel', // Android
// fallbackLabel: 'Show Passcode', // iOS (if empty, then label is hidden)
// unifiedErrors: false, // use unified error messages (default false)
// passcodeFallback: false, // iOS - allows the device to fall back to using the passcode, if faceid/touch is not available. this does not mean that if touchid/faceid fails the first few times it will revert to passcode, rather that if the former are not enrolled, then it will use the passcode.
// };
let fingerprintLableForOS = Platform.OS == "ios" ? "Touch ID" : "Fingerprint";
TouchID.authenticate('Login to [appname] using ' + fingerprintLableForOS)
.then(success => {
// console.log('Authenticated Successfully', success)
resolve(success)
})
.catch(error => {
console.log('Authentication Failed', error.code)
reject(error)
});
});
}
import * as Keychain from 'react-native-keychain';
import { Platform } from "react-native";
export const setCredentials = async (username, password) => {
return new Promise((resolve, reject) => {
// Store the credentials
Keychain.setGenericPassword(username, password)
.then(resp => {
resolve(true)
})
.catch(err => {
console.log("err: ", err);
reject(err);
});
});
}
export const getCredentials = async () => {
return new Promise((resolve, reject) => {
Keychain.getGenericPassword()
.then((credentials) => {
if (credentials && credentials.username) {
// console.log('Credentials successfully loaded for user ' + credentials.username);
resolve(credentials);
} else {
// console.log('No credentials stored');
resolve(null);
}
})
.catch(err => {
console.log("err: ", err);
reject(err);
});
});
}
...@@ -692,9 +692,9 @@ ...@@ -692,9 +692,9 @@
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@^7.7.2": "@babel/runtime@^7.7.2":
version "7.13.10" version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.5.tgz#665450911c6031af38f81db530f387ec04cd9a98"
integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw== integrity sha512-121rumjddw9c3NCQ55KGkyE1h/nzWhU/owjhw0l4mQrkzz4x9SGS1X8gFLraHwX7td3Yo4QTL+qj0NcIzN87BA==
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
...@@ -2590,7 +2590,7 @@ chalk@^3.0.0: ...@@ -2590,7 +2590,7 @@ chalk@^3.0.0:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.1.0" supports-color "^7.1.0"
chalk@^4.0.0, chalk@^4.1.0: chalk@^4.0.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz"
integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
...@@ -2598,6 +2598,14 @@ chalk@^4.0.0, chalk@^4.1.0: ...@@ -2598,6 +2598,14 @@ chalk@^4.0.0, chalk@^4.1.0:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.1.0" supports-color "^7.1.0"
chalk@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
char-regex@^1.0.2: char-regex@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz"
...@@ -6811,10 +6819,10 @@ react-native-autocomplete-input@^5.0.0: ...@@ -6811,10 +6819,10 @@ react-native-autocomplete-input@^5.0.0:
resolved "https://registry.yarnpkg.com/react-native-autocomplete-input/-/react-native-autocomplete-input-5.0.0.tgz#2bcba7be7846fe84e1e753362e3fe40c86fd7c46" resolved "https://registry.yarnpkg.com/react-native-autocomplete-input/-/react-native-autocomplete-input-5.0.0.tgz#2bcba7be7846fe84e1e753362e3fe40c86fd7c46"
integrity sha512-JsVm1rLNdyf2mLN0cw8XKTP6xwsCw+laPOxb7j81XOZhsS7nQaWytwp6+YEvSi3bnMRuUpvOUbCiS55av9/0/w== integrity sha512-JsVm1rLNdyf2mLN0cw8XKTP6xwsCw+laPOxb7j81XOZhsS7nQaWytwp6+YEvSi3bnMRuUpvOUbCiS55av9/0/w==
react-native-bootsplash@^3.2.0: react-native-bootsplash@^3.2.3:
version "3.2.0" version "3.2.3"
resolved "https://registry.yarnpkg.com/react-native-bootsplash/-/react-native-bootsplash-3.2.0.tgz#671861fdd75444f91196d3e64d3539ef50c3a30f" resolved "https://registry.yarnpkg.com/react-native-bootsplash/-/react-native-bootsplash-3.2.3.tgz#5f985a492696e14c73dc3b8475be5385b7436593"
integrity sha512-1+xMWLxqIUPbKiiwrbiekw3uKtuyNpm0R1eg5p3/ISRMXs0eZy7DHfiyCqcLq1N1a3Gv0oTZn1E7WEA2NjgdhA== integrity sha512-JNuDZ1sL9kppFrZ4OcK/ZM6gf9h5NmM6VfsLJEfa/lSPlD5wXoOyXIaeBn/6odaIPxSp31WIryeaNiZZIltu7g==
dependencies: dependencies:
chalk "^4.1.0" chalk "^4.1.0"
fs-extra "^9.1.0" fs-extra "^9.1.0"
...@@ -6884,6 +6892,11 @@ react-native-iphone-x-helper@^1.3.0: ...@@ -6884,6 +6892,11 @@ react-native-iphone-x-helper@^1.3.0:
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz" resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz"
integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg== integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==
react-native-keychain@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/react-native-keychain/-/react-native-keychain-7.0.0.tgz#11fd559fe86ae89f934b8c75ae228247deed5494"
integrity sha512-tH26sgW4OxB/llXmhO+DajFISEUoF1Ip2+WSDMIgCt8SP1xRE81m2qFzgIOc/7StYsUERxHhDPkxvq2H0/Goig==
react-native-linear-gradient@^2.5.6: react-native-linear-gradient@^2.5.6:
version "2.5.6" version "2.5.6"
resolved "https://registry.yarnpkg.com/react-native-linear-gradient/-/react-native-linear-gradient-2.5.6.tgz#96215cbc5ec7a01247a20890888aa75b834d44a0" resolved "https://registry.yarnpkg.com/react-native-linear-gradient/-/react-native-linear-gradient-2.5.6.tgz#96215cbc5ec7a01247a20890888aa75b834d44a0"
...@@ -6936,6 +6949,11 @@ react-native-screens@^2.17.1: ...@@ -6936,6 +6949,11 @@ react-native-screens@^2.17.1:
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.18.0.tgz" resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.18.0.tgz"
integrity sha512-8+lCEsxzSu55GWRw6yZpyt3OszxN1OngfBsFXdqspaEfq6uIChanzlcD2PLVQl+iN82GAcrZM800Kd1pA477ZQ== integrity sha512-8+lCEsxzSu55GWRw6yZpyt3OszxN1OngfBsFXdqspaEfq6uIChanzlcD2PLVQl+iN82GAcrZM800Kd1pA477ZQ==
react-native-segmented-control-tab@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/react-native-segmented-control-tab/-/react-native-segmented-control-tab-3.4.1.tgz#b6e54b8975ce8092315c9b0a1ab58b834d8ccf8e"
integrity sha512-BNPdlE9Unr0Xabewn8W+FhBMLjssXy9Ey7S7AY0hXlrKrEKFdC9z0yT+eEWd5dLam4T6T4IuGL8b7ZF4uGyWNw==
react-native-simple-radio-button@^2.7.4: react-native-simple-radio-button@^2.7.4:
version "2.7.4" version "2.7.4"
resolved "https://registry.yarnpkg.com/react-native-simple-radio-button/-/react-native-simple-radio-button-2.7.4.tgz#86e2dbe8af9e6bf60eee088f60466f7a975e7758" resolved "https://registry.yarnpkg.com/react-native-simple-radio-button/-/react-native-simple-radio-button-2.7.4.tgz#86e2dbe8af9e6bf60eee088f60466f7a975e7758"
...@@ -6953,6 +6971,11 @@ react-native-tab-view@^2.15.2: ...@@ -6953,6 +6971,11 @@ react-native-tab-view@^2.15.2:
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-2.15.2.tgz" resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-2.15.2.tgz"
integrity sha512-2hxLkBnZtEKFDyfvNO5EUywhy3f/EiLOBO8SWqKj4BMBTO0QwnybaPE5MVF00Fhz+VA4+h/iI40Dkrrtq70dGg== integrity sha512-2hxLkBnZtEKFDyfvNO5EUywhy3f/EiLOBO8SWqKj4BMBTO0QwnybaPE5MVF00Fhz+VA4+h/iI40Dkrrtq70dGg==
react-native-touch-id@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-native-touch-id/-/react-native-touch-id-4.4.1.tgz#8b1bb2d04c30bac36bb9696d2d723e719c4a8b08"
integrity sha512-1jTl8fC+0fxvqegy/XXTyo6vMvPhjzkoDdaqoYZx0OH8AT250NuXnNPyKktvigIcys3+2acciqOeaCall7lrvg==
react-native-vector-icons@^8.0.0: react-native-vector-icons@^8.0.0:
version "8.1.0" version "8.1.0"
resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-8.1.0.tgz" resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-8.1.0.tgz"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment