├── .watchmanconfig ├── README.md ├── assets ├── bg.png ├── bg-blur.png ├── launch.png ├── logo-bg.png ├── logo-sm.png ├── hamburger.png ├── hamburger-sm.png ├── menu_burger.png └── control-panel.png ├── menu_burger.png ├── ios ├── BVNK │ ├── Images.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Icon-App@2x.png │ │ │ ├── Icon-App@3x.png │ │ │ ├── Icon-Spotlight@2x.png │ │ │ ├── Icon-Spotlight@3x.png │ │ │ ├── Icon-Spotlight@2x-1.png │ │ │ ├── Icon-Spotlight@3x-1.png │ │ │ └── Contents.json │ │ ├── LaunchImage.launchimage │ │ │ ├── Default@2x.png │ │ │ ├── Default-568h@2x.png │ │ │ ├── Default-667h@2x.png │ │ │ ├── Default-Landscape.png │ │ │ ├── Default-Portrait.png │ │ │ ├── Default-Landscape@2x.png │ │ │ ├── Default-Portrait@2x.png │ │ │ ├── Default-Landscape-736h@3x.png │ │ │ ├── Default-Portrait-736h@3x.png │ │ │ └── Contents.json │ │ └── Brand Assets.launchimage │ │ │ └── Contents.json │ ├── BVNK.entitlements │ ├── AppDelegate.h │ ├── main.m │ ├── Info.plist │ ├── Base.lproj │ │ └── LaunchScreen.xib │ └── AppDelegate.m ├── BVNKTests │ ├── Info.plist │ └── BVNKTests.m └── BVNK.xcodeproj │ └── xcshareddata │ └── xcschemes │ ├── BVNK.xcscheme │ └── BankReact.xcscheme ├── android ├── app │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ └── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ ├── bvnk │ │ │ └── MainActivity.java │ │ │ └── bankreact │ │ │ └── MainActivity.java │ ├── proguard-rules.pro │ ├── react.gradle │ ├── build.gradle │ └── app.iml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle ├── build.gradle ├── android.iml ├── gradle.properties ├── BankReact.iml ├── gradlew.bat └── gradlew ├── fix_maps_linking.sh ├── style ├── drawer.js ├── tabs.js ├── main.js ├── navbar.js ├── forms.js ├── buttons.js ├── 4s │ └── loginRegister.js ├── transaction.js ├── controlPanel.js ├── loginRegister.js └── global.js ├── .gitignore ├── package.json ├── libs ├── device.js ├── RealmDB.js └── BankClient.js ├── MainSettingsView.js ├── styles.js ├── index.android.js ├── MainAboutView.js ├── TestLandingView.js ├── ContactView.js ├── ControlPanel.js ├── .flowconfig ├── MainContactsView.js ├── LoginRegisterView.js ├── index.ios.js ├── DrawerView.js ├── MainPaymentDepositView.js ├── MainPaymentCreditView.js ├── AddContactView.js ├── CreateAuthView.js ├── MainTransactionsView.js ├── TransactionView.js ├── RegisterView.js ├── FetchAccountView.js ├── LoginView.js └── MainAccountView.js /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bank-react 2 | -------------------------------------------------------------------------------- /assets/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/assets/bg.png -------------------------------------------------------------------------------- /menu_burger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/menu_burger.png -------------------------------------------------------------------------------- /assets/bg-blur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/assets/bg-blur.png -------------------------------------------------------------------------------- /assets/launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/assets/launch.png -------------------------------------------------------------------------------- /assets/logo-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/assets/logo-bg.png -------------------------------------------------------------------------------- /assets/logo-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/assets/logo-sm.png -------------------------------------------------------------------------------- /assets/hamburger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/assets/hamburger.png -------------------------------------------------------------------------------- /assets/hamburger-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/assets/hamburger-sm.png -------------------------------------------------------------------------------- /assets/menu_burger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/assets/menu_burger.png -------------------------------------------------------------------------------- /assets/control-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/assets/control-panel.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | BankReact 5 | 6 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-App@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-App@2x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-App@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-App@3x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default@2x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-Spotlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-Spotlight@2x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-Spotlight@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-Spotlight@3x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-Spotlight@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-Spotlight@2x-1.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-Spotlight@3x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/AppIcon.appiconset/Icon-Spotlight@3x-1.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NXRSE/bank-react/HEAD/ios/BVNK/Images.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png -------------------------------------------------------------------------------- /fix_maps_linking.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | sed -i -e 's/React\/RCTComponent.h/RCTComponent.h/g' ./node_modules/react-native-maps/ios/AirMaps/AIRMap.h 4 | sed -i -e 's/React\/RCTView.h/RCTView.h/g' ./node_modules/react-native-maps/ios/AirMaps/AIRMapCallout.h 5 | -------------------------------------------------------------------------------- /style/drawer.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var exports = module.exports = {}; 4 | 5 | exports.drawerStyles = { 6 | drawer: { 7 | shadowColor: "#000000", 8 | shadowOpacity: 0.8, 9 | shadowRadius: 0, 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /ios/BVNK/BVNK.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.in-app-payments 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /style/tabs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import { StyleSheet } from 'react-native'; 5 | 6 | module.exports = StyleSheet.create({ 7 | tabContent: { 8 | flex: 1, 9 | alignItems: 'center', 10 | }, 11 | tabText: { 12 | color: 'white', 13 | margin: 50, 14 | }, 15 | }); 16 | 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | realm/* 25 | 26 | # Android/IJ 27 | # 28 | .idea 29 | .gradle 30 | local.properties 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | -------------------------------------------------------------------------------- /style/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import { StyleSheet, Dimensions } from 'react-native'; 5 | 6 | var width = Dimensions.get('window').width; //full width 7 | var height = Dimensions.get('window').height; //full height 8 | 9 | module.exports = StyleSheet.create({ 10 | base: { 11 | flex: 1, 12 | backgroundColor: '#CCC', 13 | }, 14 | backgroundImage: { 15 | flex: 1, 16 | resizeMode: 'cover', 17 | width: width 18 | }, 19 | }); 20 | 21 | -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/Brand Assets.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "minimum-system-version" : "7.0", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "orientation" : "portrait", 11 | "idiom" : "iphone", 12 | "minimum-system-version" : "7.0", 13 | "subtype" : "retina4", 14 | "scale" : "2x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /ios/BVNK/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'BVNK' 2 | 3 | include ':app' 4 | include ':react-native-push-notification' 5 | project(':react-native-push-notification').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-push-notification/android') 6 | include ':react-native-maps' 7 | project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/android') 8 | include ':realm' 9 | project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android') 10 | -------------------------------------------------------------------------------- /ios/BVNK/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BVNK", 3 | "version": "0.0.3", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start" 7 | }, 8 | "dependencies": { 9 | "react": "~15.2.1", 10 | "react-addons-pure-render-mixin": "~15.2.1", 11 | "react-native": "~0.31.0", 12 | "react-native-button": "^1.4.2", 13 | "react-native-device": "^1.0.1", 14 | "react-native-drawer": "^2.2.6", 15 | "react-native-maps": "^0.7.1", 16 | "react-native-push-notification": "2.0.2", 17 | "react-native-router-flux": "^3.3.4", 18 | "realm": "^0.14.0" 19 | }, 20 | "devDependencies": { 21 | "rnpm-plugin-upgrade": "^0.26.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$projectDir/../../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /style/navbar.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import { StyleSheet } from 'react-native'; 5 | 6 | module.exports = StyleSheet.create({ 7 | mainContainer: { 8 | flex: 1 9 | }, 10 | base: { 11 | backgroundColor: 'transparent', 12 | borderColor: 'transparent', 13 | borderBottomWidth: 0, 14 | flexDirection: 'column', 15 | }, 16 | title: { 17 | color: 'white', 18 | textAlign: 'center', 19 | borderColor: 'transparent', 20 | borderWidth: 0, 21 | fontWeight: 'bold', 22 | }, 23 | buttonText: { 24 | borderColor: 'transparent', 25 | borderWidth: 0, 26 | }, 27 | buttonIcon: { 28 | borderColor: 'transparent', 29 | borderWidth: 0, 30 | }, 31 | }); 32 | -------------------------------------------------------------------------------- /android/android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /style/forms.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import { StyleSheet } from 'react-native'; 5 | 6 | module.exports = StyleSheet.create({ 7 | input: { 8 | fontFamily: 'Berlin', 9 | borderColor: '#515152', 10 | height: 40, 11 | borderWidth: 40, 12 | flex: 1 13 | }, 14 | inputText: { 15 | fontFamily: 'ArticulatCF-Light', 16 | borderColor: '#0b5a87', 17 | backgroundColor: 'rgba(255,255,255,0.15)', 18 | height: 40, 19 | borderWidth: 1, 20 | borderRadius: 20, 21 | marginLeft: 50, 22 | marginRight: 50, 23 | marginTop: 10, 24 | marginBottom: 10, 25 | color: 'white', 26 | paddingLeft: 20, 27 | paddingRight: 20, 28 | paddingTop: 0, 29 | paddingBottom: 0, 30 | } 31 | }); 32 | 33 | 34 | -------------------------------------------------------------------------------- /ios/BVNKTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /android/BankReact.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-Spotlight@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-Spotlight@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-Spotlight@2x-1.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-Spotlight@3x-1.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App@3x.png", 37 | "scale" : "3x" 38 | } 39 | ], 40 | "info" : { 41 | "version" : 1, 42 | "author" : "xcode" 43 | } 44 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/bvnk/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.bvnk; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.facebook.react.ReactPackage; 5 | import com.facebook.react.shell.MainReactPackage; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | public class MainActivity extends ReactActivity { 11 | 12 | /** 13 | * Returns the name of the main component registered from JavaScript. 14 | * This is used to schedule rendering of the component. 15 | */ 16 | @Override 17 | protected String getMainComponentName() { 18 | return "BVNK"; 19 | } 20 | 21 | /** 22 | * Returns whether dev mode should be enabled. 23 | * This enables e.g. the dev menu. 24 | */ 25 | @Override 26 | protected boolean getUseDeveloperSupport() { 27 | return BuildConfig.DEBUG; 28 | } 29 | 30 | /** 31 | * A list of packages used by the app. If the app uses additional views 32 | * or modules besides the default ones, add more packages here. 33 | */ 34 | @Override 35 | protected List getPackages() { 36 | return Arrays.asList( 37 | new MainReactPackage() 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /libs/device.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Device = require('react-native-device'); 4 | 5 | function DeviceLib() { 6 | 7 | this.get = function() { 8 | let deviceV = Device.deviceVersion; 9 | var device = ""; 10 | 11 | switch(deviceV) { 12 | case "4,1": 13 | device = "4s"; 14 | break; 15 | case "5,1": 16 | case "5,2": 17 | device = "5"; 18 | break; 19 | case "5,3": 20 | case "5,4": 21 | device = "5c"; 22 | break; 23 | case "6,1": 24 | case "6,2": 25 | device = "5s"; 26 | break; 27 | case "7,1": 28 | device = "6+"; 29 | break; 30 | case "7,2": 31 | device = "6"; 32 | break; 33 | case "8,2": 34 | device = "6s+"; 35 | break; 36 | case "8,1": 37 | default: 38 | device = "6s"; 39 | break; 40 | } 41 | 42 | // TESTING 43 | device = "4s"; 44 | return device; 45 | } 46 | } 47 | 48 | module.exports = DeviceLib; 49 | -------------------------------------------------------------------------------- /MainSettingsView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | ListView, 12 | Image, 13 | TouchableOpacity, 14 | Alert 15 | } from 'react-native'; 16 | 17 | import Button from 'react-native-button' 18 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 19 | import Drawer from 'react-native-drawer' 20 | 21 | let styles = require('./styles'); 22 | let BankClient = require('./libs/BankClient'); 23 | let bc = new BankClient(); 24 | let db = require('./libs/RealmDB'); 25 | let dismissKeyboard = require('dismissKeyboard'); 26 | 27 | var MainSettingsView = React.createClass({ 28 | render: function() { 29 | return( 30 | 31 | 32 | 33 | 34 | 35 | 36 | SETTINGS 37 | 38 | 39 | 40 | ) 41 | } 42 | }); 43 | 44 | module.exports = MainSettingsView; 45 | 46 | -------------------------------------------------------------------------------- /ios/BVNK/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "extent": "full-screen", 5 | "idiom": "iphone", 6 | "filename": "Default-568h@2x.png", 7 | "minimum-system-version": "7.0", 8 | "orientation": "portrait", 9 | "scale": "2x", 10 | "subtype": "retina4" 11 | }, 12 | { 13 | "extent": "full-screen", 14 | "idiom": "iphone", 15 | "filename": "Default-667h@2x.png", 16 | "minimum-system-version": "8.0", 17 | "orientation": "portrait", 18 | "scale": "2x", 19 | "subtype": "667h" 20 | }, 21 | { 22 | "extent": "full-screen", 23 | "idiom": "iphone", 24 | "filename": "Default-Landscape-736h@3x.png", 25 | "minimum-system-version": "8.0", 26 | "orientation": "landscape", 27 | "scale": "3x", 28 | "subtype": "736h" 29 | }, 30 | { 31 | "extent": "full-screen", 32 | "idiom": "iphone", 33 | "filename": "Default-Portrait-736h@3x.png", 34 | "minimum-system-version": "8.0", 35 | "orientation": "portrait", 36 | "scale": "3x", 37 | "subtype": "736h" 38 | }, 39 | { 40 | "extent": "full-screen", 41 | "idiom": "iphone", 42 | "filename": "Default@2x.png", 43 | "minimum-system-version": "7.0", 44 | "orientation": "portrait", 45 | "scale": "2x" 46 | } 47 | ], 48 | "info": { 49 | "version": 1, 50 | "author": "xcode" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /style/buttons.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import { StyleSheet } from 'react-native'; 5 | 6 | module.exports = StyleSheet.create({ 7 | containerFilled: { 8 | padding:10, 9 | height:45, 10 | borderRadius: 20, 11 | overflow:'hidden', 12 | backgroundColor: '#031d2c', 13 | paddingTop: 17, 14 | paddingBottom: 20, 15 | marginTop: 15, 16 | marginBottom: 15, 17 | marginLeft: 50, 18 | marginRight: 50, 19 | }, 20 | containerBase: { 21 | padding:10, 22 | height:45, 23 | overflow:'hidden', 24 | borderRadius: 20, 25 | borderColor: '#515152', 26 | borderWidth: 1, 27 | backgroundColor: 'transparent', 28 | paddingTop: 13, 29 | paddingBottom: 20, 30 | marginTop: 15, 31 | marginBottom: 15, 32 | marginLeft: 50, 33 | marginRight: 50, 34 | }, 35 | containerBaseNoBorder: { 36 | padding:10, 37 | height:45, 38 | overflow:'hidden', 39 | borderRadius: 20, 40 | borderWidth: 0, 41 | backgroundColor: 'transparent', 42 | paddingTop: 17, 43 | paddingBottom: 20, 44 | marginTop: 15, 45 | marginBottom: 15, 46 | marginLeft: 50, 47 | marginRight: 50, 48 | }, 49 | containerNotification: { 50 | backgroundColor: 'transparent', 51 | }, 52 | base: { 53 | fontSize: 12, 54 | color: 'white' 55 | }, 56 | }); 57 | -------------------------------------------------------------------------------- /ios/BVNK/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | co.bvnk.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 5 23 | LSApplicationCategoryType 24 | 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | 32 | NSLocationWhenInUseUsageDescription 33 | 34 | UIAppFonts 35 | 36 | Berlin.ttf 37 | ArticulatCF-Light.otf 38 | 39 | UILaunchStoryboardName 40 | LaunchScreen 41 | UIRequiredDeviceCapabilities 42 | 43 | armv7 44 | 45 | UISupportedInterfaceOrientations 46 | 47 | UIInterfaceOrientationPortrait 48 | 49 | UIViewControllerBasedStatusBarAppearance 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /style/4s/loginRegister.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { StyleSheet, Dimensions } from 'react-native'; 4 | 5 | var width = Dimensions.get('window').width; //full width 6 | var height = Dimensions.get('window').height; //full height 7 | 8 | module.exports = StyleSheet.create({ 9 | base: { 10 | flex: 1, 11 | backgroundColor: '#CCC', 12 | }, 13 | backgroundImage: { 14 | flex: 1, 15 | resizeMode: 'cover', 16 | width: width 17 | }, 18 | bigLogoWrap: { 19 | alignItems: 'center', 20 | justifyContent: 'center', 21 | marginBottom: -120, 22 | }, 23 | bigLogo: { 24 | resizeMode: 'contain', 25 | width: 100, 26 | marginTop: -80, 27 | }, 28 | smallLogoWrap: { 29 | alignItems: 'center', 30 | justifyContent: 'center', 31 | }, 32 | smallLogo: { 33 | resizeMode: 'contain', 34 | marginTop: 5, 35 | width: 80, 36 | }, 37 | buttonsLoginRegister: { 38 | paddingTop: 20, 39 | paddingBottom: 20, 40 | paddingLeft: 50, 41 | paddingRight: 50, 42 | flexDirection: 'column' 43 | }, 44 | buttonsLogin: { 45 | flex: 1, 46 | borderColor: 'black', 47 | borderStyle: 'solid', 48 | borderWidth: 1, 49 | paddingTop: 5, 50 | paddingBottom:5 51 | }, 52 | buttonsRegister: { 53 | flex: 1, 54 | borderColor: 'black', 55 | borderStyle: 'solid', 56 | borderWidth: 1, 57 | paddingTop: 5, 58 | paddingBottom: 5 59 | }, 60 | buttonText: { 61 | textAlign: 'center', 62 | } 63 | }); 64 | 65 | -------------------------------------------------------------------------------- /styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { StyleSheet } from 'react-native'; 4 | 5 | module.exports = { 6 | global: require('./style/global'), 7 | navbar: require('./style/navbar'), 8 | landingPage: require('./style/loginRegister'), 9 | buttons: require('./style/buttons'), 10 | forms: require('./style/forms'), 11 | main: require('./style/main'), 12 | tabs: require('./style/tabs'), 13 | controlPanel: require('./style/controlPanel'), 14 | transaction: require('./style/transaction'), 15 | }; 16 | 17 | /* 18 | let deviceLib = require('./libs/device'); 19 | // Get device 20 | let deviceC = new deviceLib(); 21 | let device = deviceC.get(); 22 | 23 | if (device == "4s") { 24 | module.exports = { 25 | global: require('./style/global'), 26 | navbar: require('./style/navbar'), 27 | landingPage: require('./style/4s/loginRegister'), 28 | buttons: require('./style/buttons'), 29 | forms: require('./style/forms'), 30 | main: require('./style/main'), 31 | tabs: require('./style/tabs'), 32 | controlPanel: require('./style/controlPanel'), 33 | transaction: require('./style/transaction'), 34 | }; 35 | } else { 36 | module.exports = { 37 | global: require('./style/global'), 38 | navbar: require('./style/navbar'), 39 | landingPage: require('./style/loginRegister'), 40 | buttons: require('./style/buttons'), 41 | forms: require('./style/forms'), 42 | main: require('./style/main'), 43 | tabs: require('./style/tabs'), 44 | controlPanel: require('./style/controlPanel'), 45 | transaction: require('./style/transaction'), 46 | }; 47 | } 48 | */ 49 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/bankreact/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.bankreact; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage; 5 | import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage; 6 | import com.airbnb.android.react.maps.MapsPackage; 7 | import io.realm.react.RealmReactPackage; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.shell.MainReactPackage; 10 | 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | public class MainActivity extends ReactActivity { 15 | 16 | /** 17 | * Returns the name of the main component registered from JavaScript. 18 | * This is used to schedule rendering of the component. 19 | */ 20 | @Override 21 | protected String getMainComponentName() { 22 | return "BankReact"; 23 | } 24 | 25 | /** 26 | * Returns whether dev mode should be enabled. 27 | * This enables e.g. the dev menu. 28 | */ 29 | @Override 30 | protected boolean getUseDeveloperSupport() { 31 | return BuildConfig.DEBUG; 32 | } 33 | 34 | /** 35 | * A list of packages used by the app. If the app uses additional views 36 | * or modules besides the default ones, add more packages here. 37 | */ 38 | @Override 39 | protected List getPackages() { 40 | return Arrays.asList( 41 | new MainReactPackage(), 42 | new ReactNativePushNotificationPackage(this), 43 | new ReactNativePushNotificationPackage(this), 44 | new MapsPackage(), 45 | new RealmReactPackage() 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /style/transaction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import { StyleSheet, Dimensions } from 'react-native'; 5 | 6 | var width = Dimensions.get('window').width; //full width 7 | var height = Dimensions.get('window').height; //full height 8 | 9 | module.exports = StyleSheet.create({ 10 | container: { 11 | flex: 1, 12 | flexDirection: 'column', 13 | alignItems: 'stretch', 14 | backgroundColor: 'transparent', 15 | borderRadius: 15, 16 | borderWidth: 0, 17 | borderBottomColor: 'white', 18 | borderBottomWidth: 1, 19 | borderColor: 'transparent', 20 | paddingTop: 5, 21 | paddingBottom: 5, 22 | marginLeft: 40, 23 | marginRight: 40, 24 | marginTop: 10, 25 | marginBottom: 10, 26 | }, 27 | list: { 28 | marginTop: 0, 29 | paddingTop: 0, 30 | flex: 1, 31 | flexDirection: 'column', 32 | // @FIXME Find element that is forcing negative margins 33 | marginTop: -950, 34 | }, 35 | desc: { 36 | textAlign: 'left', 37 | fontFamily: 'ArticulatCF-Light', 38 | fontSize: 20, 39 | color: 'white', 40 | marginLeft: 10, 41 | backgroundColor: 'transparent', 42 | }, 43 | time: { 44 | textAlign: 'right', 45 | fontFamily: 'ArticulatCF-Light', 46 | fontSize: 10, 47 | color: 'white', 48 | backgroundColor: 'transparent', 49 | marginLeft: 0, 50 | paddingTop: 5, 51 | paddingBottom: 5, 52 | }, 53 | map: { 54 | alignItems: 'center', 55 | height: 300, 56 | width: width, 57 | flex: 0, 58 | }, 59 | }); 60 | -------------------------------------------------------------------------------- /style/controlPanel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import { StyleSheet, Dimensions } from 'react-native'; 5 | 6 | var width = Dimensions.get('window').width; //full width 7 | var height = Dimensions.get('window').height; //full height 8 | 9 | module.exports = StyleSheet.create({ 10 | backgroundImage: { 11 | flex: 1, 12 | resizeMode: 'cover', 13 | width: width, 14 | height: height, 15 | }, 16 | containerFilled: { 17 | padding:10, 18 | height:45, 19 | borderRadius: 20, 20 | overflow:'hidden', 21 | backgroundColor: '#031d2c', 22 | paddingTop: 17, 23 | paddingBottom: 20, 24 | marginTop: 15, 25 | marginBottom: 15, 26 | marginLeft: 50, 27 | marginRight: 50, 28 | }, 29 | containerBase: { 30 | padding:10, 31 | height:45, 32 | overflow:'hidden', 33 | borderRadius: 20, 34 | backgroundColor: 'transparent', 35 | paddingTop: 17, 36 | paddingBottom: 20, 37 | marginTop: 15, 38 | marginBottom: 15, 39 | marginLeft: 50, 40 | marginRight: 50, 41 | }, 42 | exitContainer: { 43 | padding:10, 44 | height:60, 45 | overflow:'hidden', 46 | borderRadius: 20, 47 | borderWidth: 0, 48 | backgroundColor: 'transparent', 49 | paddingTop: 17, 50 | paddingBottom: 20, 51 | marginTop: 40, 52 | marginBottom: 20, 53 | marginLeft: 50, 54 | marginRight: 50, 55 | }, 56 | exit: { 57 | fontSize: 20, 58 | color: '#494949', 59 | }, 60 | containerNotification: { 61 | backgroundColor: 'transparent', 62 | }, 63 | base: { 64 | fontSize: 12, 65 | color: 'white' 66 | }, 67 | }); 68 | -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | Navigator 11 | } from 'react-native'; 12 | 13 | import {Actions, Scene, Router, TabBar} from 'react-native-router-flux'; 14 | 15 | StatusBar.setBarStyle('light-content'); 16 | 17 | class BVNK extends Component { 18 | render() { 19 | return 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | } 32 | } 33 | 34 | var styles = require('./styles'); 35 | // Views 36 | var LoginRegisterView = require('./LoginRegisterView'); 37 | var LoginView = require('./LoginView'); 38 | var RegisterView = require('./RegisterView'); 39 | var CreateAuthView = require('./CreateAuthView'); 40 | var MainAccountTabs = require('./MainAccountTabs'); 41 | var ContactView = require('./ContactView'); 42 | var MainPaymentCreditView = require('./MainPaymentCreditView'); 43 | var MainPaymentDepositView = require('./MainPaymentDepositView'); 44 | 45 | // DB 46 | var db = require('./libs/RealmDB'); 47 | //console.log(db.path); 48 | 49 | AppRegistry.registerComponent('BVNK', () => BVNK); 50 | -------------------------------------------------------------------------------- /MainAboutView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | ListView, 12 | Image, 13 | TouchableOpacity, 14 | Alert 15 | } from 'react-native'; 16 | 17 | import Button from 'react-native-button' 18 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 19 | import Drawer from 'react-native-drawer' 20 | 21 | let styles = require('./styles'); 22 | let BankClient = require('./libs/BankClient'); 23 | let bc = new BankClient(); 24 | let db = require('./libs/RealmDB'); 25 | let dismissKeyboard = require('dismissKeyboard'); 26 | 27 | var MainAboutView = React.createClass({ 28 | render: function() { 29 | return( 30 | 31 | 32 | 33 | 34 | 35 | 36 | ABOUT 37 | BVNK is a project to build core banking infrastructure using modern standards. To find out more, go to https://bvnk.co. 38 | All code is available on Github at https://github.com/BVNK 39 | Feel free to get in touch at hello@bvnk.co 40 | 41 | 42 | 43 | ) 44 | } 45 | }); 46 | 47 | module.exports = MainAboutView; 48 | 49 | -------------------------------------------------------------------------------- /TestLandingView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | Image, 12 | Alert 13 | } from 'react-native'; 14 | 15 | import Button from 'react-native-button' 16 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 17 | 18 | import ControlPanel from './ControlPanel' 19 | import DrawerView from './DrawerView' 20 | import MainContactsView from './MainContactsView' 21 | 22 | let styles = require('./styles'); 23 | let BankClient = require('./libs/BankClient'); 24 | let bc = new BankClient(); 25 | let db = require('./libs/RealmDB'); 26 | let dismissKeyboard = require('dismissKeyboard'); 27 | 28 | var TestLandingView = React.createClass({ 29 | getInitialState() { 30 | dismissKeyboard(); 31 | return { 32 | balance: "nil", 33 | drawerOpen: false, 34 | } 35 | }, 36 | 37 | updateStateListener: function() { 38 | // Fetch account 39 | let user = db.objects('Account'); 40 | var userAccount = user.slice(0,1); 41 | userAccount = userAccount[0]; 42 | console.log(userAccount.AccountBalance); 43 | this.setState({ 'balance' : userAccount.AccountBalance }); 44 | }, 45 | 46 | componentDidMount: function() { 47 | // Observe Realm Change Events 48 | db.addListener('change', this.updateStateListener); 49 | }, 50 | 51 | componentWillUnmount: function() { 52 | // Remove the listener 53 | db.removeListener('change', this.updateStateListener); 54 | }, 55 | 56 | closeDrawer() { 57 | this._drawer.close() 58 | }, 59 | 60 | openDrawer() { 61 | this._drawer.open() 62 | }, 63 | 64 | render: function() { 65 | 66 | return ( 67 | 68 | ) 69 | } 70 | }); 71 | 72 | module.exports = TestLandingView; 73 | -------------------------------------------------------------------------------- /style/loginRegister.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import { StyleSheet, Dimensions } from 'react-native'; 5 | //let deviceLib = require('./../libs/device'); 6 | 7 | var width = Dimensions.get('window').width; //full width 8 | var height = Dimensions.get('window').height; //full height 9 | // Get device 10 | //let deviceC = new deviceLib(); 11 | //let device = deviceC.get(); 12 | 13 | var buttonMarginOffset = (height < 1000) ? -150 : 0; 14 | var logoMarginOffset = (height < 1000) ? -40 : 0; 15 | 16 | module.exports = StyleSheet.create({ 17 | base: { 18 | flex: 1, 19 | backgroundColor: '#CCC', 20 | }, 21 | backgroundImage: { 22 | flex: 1, 23 | resizeMode: 'cover', 24 | width: width, 25 | height: height, 26 | }, 27 | bigLogoWrap: { 28 | alignItems: 'center', 29 | justifyContent: 'center', 30 | marginBottom: buttonMarginOffset, 31 | }, 32 | bigLogo: { 33 | resizeMode: 'contain', 34 | width: 150, 35 | marginTop: logoMarginOffset, 36 | }, 37 | smallLogoWrap: { 38 | alignItems: 'center', 39 | justifyContent: 'center', 40 | }, 41 | smallLogo: { 42 | resizeMode: 'contain', 43 | marginTop: 5, 44 | width: 80, 45 | }, 46 | buttonsLoginRegister: { 47 | paddingTop: 40, 48 | paddingBottom: 40, 49 | paddingLeft: 50, 50 | paddingRight: 50, 51 | flexDirection: 'column' 52 | }, 53 | buttonsLogin: { 54 | flex: 1, 55 | borderColor: 'black', 56 | borderStyle: 'solid', 57 | borderWidth: 1, 58 | paddingTop: 10, 59 | paddingBottom: 10 60 | }, 61 | buttonsRegister: { 62 | flex: 1, 63 | borderColor: 'black', 64 | borderStyle: 'solid', 65 | borderWidth: 1, 66 | paddingTop: 10, 67 | paddingBottom: 10 68 | }, 69 | buttonText: { 70 | textAlign: 'center', 71 | } 72 | }); 73 | 74 | -------------------------------------------------------------------------------- /ContactView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | 5 | import { 6 | AppRegistry, 7 | Text, 8 | View, 9 | StatusBar, 10 | StyleSheet, 11 | TextInput, 12 | Image, 13 | Alert 14 | } from 'react-native'; 15 | 16 | import Button from 'react-native-button' 17 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 18 | 19 | let styles = require('./styles'); 20 | let BankClient = require('./libs/BankClient'); 21 | let bc = new BankClient(); 22 | let db = require('./libs/RealmDB'); 23 | let dismissKeyboard = require('dismissKeyboard'); 24 | 25 | var ContactView = React.createClass({ 26 | getInitialState() { 27 | dismissKeyboard(); 28 | return { 29 | data: { ContactName: "nil" } 30 | } 31 | }, 32 | 33 | render: function() { 34 | 35 | return ( 36 | 37 | 38 | 39 | 40 | 41 | 42 | {this.props.data.ContactName} 43 | Account Number: 44 | {this.props.data.ContactAccountNumber} 45 | Bank Number: 46 | {this.props.data.ContactBankNumber} 47 | 48 | 51 | 52 | 53 | 54 | ) 55 | } 56 | }); 57 | 58 | module.exports = ContactView; 59 | -------------------------------------------------------------------------------- /ControlPanel.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { 3 | ScrollView, 4 | StyleSheet, 5 | Text, 6 | TouchableOpacity, 7 | Image, 8 | View, 9 | } from 'react-native' 10 | 11 | import Button from 'react-native-button' 12 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 13 | 14 | let styles = require('./styles'); 15 | 16 | export default class ControlPanel extends Component { 17 | static propTypes = { 18 | closeDrawer: PropTypes.func.isRequired 19 | }; 20 | 21 | render() { 22 | let {closeDrawer} = this.props 23 | return ( 24 | 25 | 26 | 30 | 31 | 33 | 35 | 37 | 39 | 41 | 43 | 44 | 45 | ) 46 | } 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | # We fork some components by platform. 4 | .*/*.web.js 5 | .*/*.android.js 6 | 7 | # Some modules have their own node_modules with overlap 8 | .*/node_modules/node-haste/.* 9 | 10 | # Ugh 11 | .*/node_modules/babel.* 12 | .*/node_modules/babylon.* 13 | .*/node_modules/invariant.* 14 | 15 | # Ignore react and fbjs where there are overlaps, but don't ignore 16 | # anything that react-native relies on 17 | .*/node_modules/fbjs/lib/Map.js 18 | .*/node_modules/fbjs/lib/fetch.js 19 | .*/node_modules/fbjs/lib/ExecutionEnvironment.js 20 | .*/node_modules/fbjs/lib/ErrorUtils.js 21 | 22 | # Flow has a built-in definition for the 'react' module which we prefer to use 23 | # over the currently-untyped source 24 | .*/node_modules/react/react.js 25 | .*/node_modules/react/lib/React.js 26 | .*/node_modules/react/lib/ReactDOM.js 27 | 28 | .*/__mocks__/.* 29 | .*/__tests__/.* 30 | 31 | .*/commoner/test/source/widget/share.js 32 | 33 | # Ignore commoner tests 34 | .*/node_modules/commoner/test/.* 35 | 36 | # See https://github.com/facebook/flow/issues/442 37 | .*/react-tools/node_modules/commoner/lib/reader.js 38 | 39 | # Ignore jest 40 | .*/node_modules/jest-cli/.* 41 | 42 | # Ignore Website 43 | .*/website/.* 44 | 45 | [include] 46 | 47 | [libs] 48 | node_modules/react-native/Libraries/react-native/react-native-interface.js 49 | 50 | [options] 51 | module.system=haste 52 | 53 | esproposal.class_static_fields=enable 54 | esproposal.class_instance_fields=enable 55 | 56 | munge_underscores=true 57 | 58 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 59 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\)$' -> 'RelativeImageStub' 60 | 61 | suppress_type=$FlowIssue 62 | suppress_type=$FlowFixMe 63 | suppress_type=$FixMe 64 | 65 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 66 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 67 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 68 | 69 | [version] 70 | 0.21.0 71 | -------------------------------------------------------------------------------- /ios/BVNKTests/BVNKTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import "RCTLog.h" 14 | #import "RCTRootView.h" 15 | 16 | #define TIMEOUT_SECONDS 240 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface BVNKTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation BVNKTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /MainContactsView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | ListView, 12 | Image, 13 | TouchableOpacity, 14 | Alert 15 | } from 'react-native'; 16 | 17 | import Button from 'react-native-button' 18 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 19 | 20 | let styles = require('./styles'); 21 | let BankClient = require('./libs/BankClient'); 22 | let bc = new BankClient(); 23 | let db = require('./libs/RealmDB'); 24 | let dismissKeyboard = require('dismissKeyboard'); 25 | 26 | var MainContactsView = React.createClass({ 27 | 28 | getInitialState: function() { 29 | dismissKeyboard(); 30 | let contacts = db.objects('Contacts'); 31 | var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); 32 | return { 33 | dataSource: ds.cloneWithRows(contacts), 34 | }; 35 | }, 36 | 37 | componentDidMount: function() { 38 | }, 39 | 40 | render: function() { 41 | return ( 42 | 43 | 44 | 45 | 46 | 47 | 48 | CONTACTS 49 | 51 | 55 | 57 | Actions.contact({ data: rowData })} 58 | style={styles.global.contactItemText}>{rowData.ContactName} 59 | } 60 | /> 61 | 62 | 63 | 64 | ) 65 | } 66 | }); 67 | 68 | module.exports = MainContactsView; 69 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | 30 | # Do not strip any method/class that is annotated with @DoNotStrip 31 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 32 | -keepclassmembers class * { 33 | @com.facebook.proguard.annotations.DoNotStrip *; 34 | } 35 | 36 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 37 | void set*(***); 38 | *** get*(); 39 | } 40 | 41 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 42 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 43 | -keepclassmembers,includedescriptorclasses class * { native ; } 44 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 45 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 46 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 47 | 48 | -dontwarn com.facebook.react.** 49 | 50 | # okhttp 51 | 52 | -keepattributes Signature 53 | -keepattributes *Annotation* 54 | -keep class com.squareup.okhttp.** { *; } 55 | -keep interface com.squareup.okhttp.** { *; } 56 | -dontwarn com.squareup.okhttp.** 57 | 58 | # okio 59 | 60 | -keep class sun.misc.Unsafe { *; } 61 | -dontwarn java.nio.file.* 62 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 63 | -dontwarn okio.** 64 | 65 | # stetho 66 | 67 | -dontwarn com.facebook.stetho.** 68 | -------------------------------------------------------------------------------- /ios/BVNK/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /LoginRegisterView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | NavigatorIOS, 11 | TouchableOpacity, 12 | PushNotificationIOS, 13 | Image, 14 | PropTypes, 15 | AlertIOS 16 | } from 'react-native'; 17 | 18 | import Button from 'react-native-button' 19 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 20 | import Drawer from 'react-native-drawer' 21 | 22 | import ControlPanel from './ControlPanel' 23 | import DrawerView from './DrawerView' 24 | 25 | var styles = require('./styles'); 26 | 27 | let dismissKeyboard = require('dismissKeyboard'); 28 | let db = require('./libs/RealmDB'); 29 | 30 | //class LoginRegisterView extends Component{ 31 | var LoginRegisterView = React.createClass({ 32 | getInitialState() { 33 | return { 34 | drawerDisabled: true 35 | } 36 | }, 37 | 38 | componentWillMount() { 39 | PushNotificationIOS.addEventListener('notification', this._onNotification); 40 | }, 41 | 42 | componentWillUnmount() { 43 | PushNotificationIOS.removeEventListener('notification', this._onNotification); 44 | }, 45 | 46 | _sendNotification() { 47 | require('RCTDeviceEventEmitter').emit('remoteNotificationReceived', { 48 | aps: { 49 | alert: 'Sample notification', 50 | badge: '+1', 51 | sound: 'default', 52 | category: 'REACT_NATIVE' 53 | }, 54 | }); 55 | }, 56 | 57 | _onNotification(notification) { 58 | AlertIOS.alert( 59 | 'Notification Received', 60 | 'Alert message: ' + notification.getMessage(), 61 | [{ 62 | text: 'Dismiss', 63 | onPress: null, 64 | }] 65 | ); 66 | }, 67 | 68 | loginOrRetrieve: function() { 69 | let userAccount = db.objects('Account'); 70 | if (userAccount.length == 0) { 71 | // There is no account set up yet 72 | // Show fetch account screen 73 | Actions.accountFetch(); 74 | return; 75 | } 76 | Actions.login(); 77 | }, 78 | 79 | render() { 80 | return ( 81 | 82 | 83 | 84 | 85 | 86 | 87 | 89 | 91 | 92 | 93 | 94 | ) 95 | } 96 | }); 97 | 98 | module.exports = LoginRegisterView; 99 | -------------------------------------------------------------------------------- /ios/BVNK/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import "RCTRootView.h" 13 | #import "RCTPushNotificationManager.h" 14 | 15 | @implementation AppDelegate 16 | 17 | // Required to register for notifications 18 | - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings 19 | { 20 | [RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings]; 21 | } 22 | // Required for the register event. 23 | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken 24 | { 25 | [RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; 26 | } 27 | // Required for the notification event. 28 | - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification 29 | { 30 | [RCTPushNotificationManager didReceiveRemoteNotification:notification]; 31 | } 32 | // Required for the localNotification event. 33 | - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification 34 | { 35 | [RCTPushNotificationManager didReceiveLocalNotification:notification]; 36 | } 37 | 38 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 39 | { 40 | NSURL *jsCodeLocation; 41 | 42 | /** 43 | * Loading JavaScript code - uncomment the one you want. 44 | * 45 | * OPTION 1 46 | * Load from development server. Start the server from the repository root: 47 | * 48 | * $ npm start 49 | * 50 | * To run on device, change `localhost` to the IP address of your computer 51 | * (you can get this by typing `ifconfig` into the terminal and selecting the 52 | * `inet` value under `en0:`) and make sure your computer and iOS device are 53 | * on the same Wi-Fi network. 54 | */ 55 | 56 | jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"]; 57 | 58 | /** 59 | * OPTION 2 60 | * Load from pre-bundled file on disk. The static bundle is automatically 61 | * generated by the "Bundle React Native code and images" build step when 62 | * running the project on an actual device or running the project on the 63 | * simulator in the "Release" build configuration. 64 | */ 65 | 66 | jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 67 | 68 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 69 | moduleName:@"BVNK" 70 | initialProperties:nil 71 | launchOptions:launchOptions]; 72 | 73 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 74 | UIViewController *rootViewController = [UIViewController new]; 75 | rootViewController.view = rootView; 76 | self.window.rootViewController = rootViewController; 77 | [self.window makeKeyAndVisible]; 78 | return YES; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /index.ios.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | Navigator, 11 | Alert 12 | } from 'react-native'; 13 | 14 | import {Actions, Scene, Router, TabBar} from 'react-native-router-flux'; 15 | 16 | StatusBar.setBarStyle('light-content'); 17 | 18 | class BVNK extends Component { 19 | 20 | render() { 21 | return 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | } 43 | } 44 | 45 | var styles = require('./styles'); 46 | // Views 47 | var DrawerView = require('./DrawerView'); 48 | var LoginRegisterView = require('./LoginRegisterView'); 49 | var LoginView = require('./LoginView'); 50 | var RegisterView = require('./RegisterView'); 51 | var CreateAuthView = require('./CreateAuthView'); 52 | var MainAccountView = require('./MainAccountView'); 53 | var ContactView = require('./ContactView'); 54 | var MainPaymentCreditView = require('./MainPaymentCreditView'); 55 | var MainPaymentDepositView = require('./MainPaymentDepositView'); 56 | var MainSettingsView = require('./MainSettingsView'); 57 | var MainContactsView = require('./MainContactsView'); 58 | var TransactionView = require('./TransactionView'); 59 | var MainTransactionView = require('./MainTransactionsView'); 60 | var AddContactView = require('./AddContactView'); 61 | var FetchAccountView = require('./FetchAccountView'); 62 | var MainAboutView = require('./MainAboutView'); 63 | 64 | // DB 65 | var db = require('./libs/RealmDB'); 66 | //console.log(db.path); 67 | 68 | AppRegistry.registerComponent('BVNK', () => BVNK); 69 | -------------------------------------------------------------------------------- /DrawerView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component, PropTypes } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | NavigatorIOS, 11 | TouchableOpacity, 12 | PushNotificationIOS, 13 | Image, 14 | AlertIOS 15 | } from 'react-native'; 16 | 17 | import Button from 'react-native-button' 18 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer, DefaultRenderer} from 'react-native-router-flux' 19 | import Drawer from 'react-native-drawer' 20 | 21 | import ControlPanel from './ControlPanel' 22 | 23 | var styles = require('./styles'); 24 | let dismissKeyboard = require('dismissKeyboard'); 25 | 26 | class DrawerView extends Component { 27 | state = { 28 | drawerOpen: false, 29 | drawerDisabled: false, 30 | side: 'left', 31 | }; 32 | 33 | closeDrawer = () => { 34 | this._drawer.close() 35 | }; 36 | 37 | openDrawer = () => { 38 | this._drawer.open() 39 | }; 40 | 41 | render() { 42 | const state = this.props.navigationState; 43 | const children = state.children; 44 | 45 | return ( 46 | this._drawer = ref} 48 | type="static" 49 | open={state.open} 50 | content={ 51 | 52 | } 53 | acceptDoubleTap 54 | styles={drawerStyles} 55 | onOpen={() => { 56 | console.log('onopen') 57 | //this.setState({drawerOpen: true}) 58 | }} 59 | onClose={() => { 60 | console.log('onclose') 61 | //this.setState({drawerOpen: false}) 62 | }} 63 | captureGestures={false} 64 | tweenDuration={100} 65 | panThreshold={0.08} 66 | disabled={true} 67 | openDrawerOffset={(viewport) => { 68 | return 0 69 | }} 70 | closedDrawerOffset={(viewport) => { 71 | return 0 72 | }} 73 | panOpenMask={0.2} 74 | tweenHandler={(ratio) => ({ 75 | mainOverlay: { opacity:(2-ratio)/2 } 76 | })} 77 | negotiatePan 78 | side={'left'} 79 | > 80 | 81 | 82 | ) 83 | } 84 | }; 85 | 86 | /* 87 | class DrawerView extends Component { 88 | 89 | closeDrawer = () => { 90 | this._drawer.close() 91 | }; 92 | 93 | openDrawer = () => { 94 | this._drawer.open() 95 | }; 96 | 97 | render(){ 98 | const state = this.props.navigationState; 99 | const children = state.children; 100 | return ( 101 | Actions.refresh({key:state.key, open: true})} 105 | onClose={()=>Actions.refresh({key:state.key, open: false})} 106 | type="displace" 107 | content={} 108 | tapToClose={true} 109 | openDrawerOffset={0.2} 110 | panCloseMask={0.2} 111 | negotiatePan={true} 112 | tweenHandler={(ratio) => ({ 113 | main: { opacity:Math.max(0.54,1-ratio) } 114 | })}> 115 | 116 | 117 | ); 118 | } 119 | } 120 | */ 121 | 122 | var drawerStyles = { 123 | drawer: { 124 | shadowColor: "#000000", 125 | shadowOpacity: 0.2, 126 | shadowRadius: 0, 127 | marginRight: 100, 128 | }, 129 | 130 | main: { 131 | shadowColor: "#000000", 132 | shadowOpacity: 0.2, 133 | shadowRadius: 0, 134 | }, 135 | 136 | mainOverlay: { 137 | } 138 | } 139 | 140 | module.exports = DrawerView; 141 | -------------------------------------------------------------------------------- /style/global.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import { StyleSheet } from 'react-native'; 5 | 6 | module.exports = StyleSheet.create({ 7 | container: { 8 | flex: 1, 9 | }, 10 | wrap: { 11 | marginTop: 40, 12 | flex: 1 13 | }, 14 | heading: { 15 | fontFamily: 'Berlin', 16 | fontSize: 15, 17 | textAlign: 'center', 18 | backgroundColor: 'transparent', 19 | color: 'white', 20 | height: 30, 21 | textDecorationLine: 'underline', 22 | }, 23 | notification: { 24 | fontFamily: 'ArticulatCF-Light', 25 | fontSize: 20, 26 | textAlign: 'center', 27 | backgroundColor: 'rgba(0, 0, 0, 0.3)', 28 | color: 'white', 29 | borderRadius: 15, 30 | borderWidth: 0, 31 | borderColor: 'transparent', 32 | paddingTop: 10, 33 | paddingBottom: 10, 34 | marginLeft: 50, 35 | marginRight: 50, 36 | }, 37 | balanceContainerWrap: { 38 | flex: 1, 39 | flexDirection: 'column', 40 | alignItems: 'center', 41 | marginLeft: 20, 42 | backgroundColor: 'transparent', 43 | borderWidth: 0, 44 | borderColor: 'transparent', 45 | }, 46 | balanceContainer: { 47 | marginTop: 0, 48 | flex: 1, 49 | flexDirection: 'row', 50 | backgroundColor: 'transparent', 51 | borderWidth: 0, 52 | borderColor: 'transparent', 53 | paddingLeft: 20, 54 | paddingRight: 50, 55 | }, 56 | balance: { 57 | fontFamily: 'Berlin', 58 | fontSize: 50, 59 | flex: 0, 60 | flexDirection: 'column', 61 | alignItems: 'center', 62 | borderWidth: 0, 63 | borderColor: 'transparent', 64 | marginTop: 10, 65 | marginBottom: 10, 66 | color: 'white', 67 | paddingTop: 0, 68 | paddingBottom: 0, 69 | }, 70 | balanceDecimal: { 71 | fontFamily: 'Berlin', 72 | fontSize: 20, 73 | flex: 0, 74 | flexDirection: 'column', 75 | alignItems: 'center', 76 | height: 20, 77 | borderWidth: 0, 78 | borderColor: 'transparent', 79 | marginTop: 10, 80 | marginBottom: 10, 81 | color: 'white', 82 | paddingTop: 0, 83 | paddingBottom: 0, 84 | }, 85 | contactItem: { 86 | backgroundColor: 'transparent', 87 | borderRadius: 15, 88 | borderWidth: 0, 89 | borderBottomColor: 'white', 90 | borderBottomWidth: 1, 91 | borderColor: 'transparent', 92 | paddingTop: 5, 93 | paddingBottom: 5, 94 | marginLeft: 40, 95 | marginRight: 40, 96 | marginTop: 10, 97 | marginBottom: 10, 98 | }, 99 | contactItemText: { 100 | textAlign: 'left', 101 | fontFamily: 'ArticulatCF-Light', 102 | fontSize: 15, 103 | color: 'white', 104 | marginLeft: 10, 105 | }, 106 | contactInfoHeading: { 107 | textAlign: 'left', 108 | fontFamily: 'ArticulatCF-Light', 109 | fontSize: 15, 110 | color: 'white', 111 | backgroundColor: 'transparent', 112 | marginLeft: 20, 113 | textDecorationLine: 'underline', 114 | paddingTop: 5, 115 | paddingBottom: 5, 116 | }, 117 | contactInfo: { 118 | textAlign: 'left', 119 | fontFamily: 'ArticulatCF-Light', 120 | fontSize: 15, 121 | color: 'white', 122 | backgroundColor: 'transparent', 123 | marginLeft: 20, 124 | paddingTop: 5, 125 | paddingBottom: 15, 126 | }, 127 | generalText: { 128 | textAlign: 'center', 129 | fontFamily: 'ArticulatCF-Light', 130 | fontSize: 15, 131 | color: 'white', 132 | backgroundColor: 'transparent', 133 | marginLeft: 20, 134 | paddingTop: 5, 135 | paddingBottom: 15, 136 | }, 137 | aboutText: { 138 | textAlign: 'center', 139 | backgroundColor: 'transparent', 140 | fontFamily: 'ArticulatCF-Light', 141 | fontSize: 25, 142 | color: 'white', 143 | marginLeft: 10, 144 | marginTop: 20, 145 | }, 146 | }); 147 | 148 | -------------------------------------------------------------------------------- /libs/RealmDB.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Realm for a database - realm.io 4 | // Encrypt database 5 | var key = new Int8Array(64); 6 | const Realm = require('realm'); 7 | //Realm.defaultPath = "/Users/ksred/Documents/Projects/Bank/ReactNative/BankReact/realm/default.realm"; 8 | 9 | // @TODO Move schemas into separate file 10 | // Set up schemas 11 | const AccountSchema = { 12 | name: 'Account', 13 | properties: { 14 | AccountNumber: { type: 'string' , indexed: true, optional: true, default: '' }, 15 | BankNumber: { type: 'string', optional: true, default: '' }, 16 | AccountHolderName: { type: 'string', optional: true, default: '' }, 17 | AccountBalance: { type: 'float', optional: true, default: 0 }, // Decimal 18 | Overdraft: { type: 'float', optional: true, default: 0 }, 19 | AvailableBalance: { type: 'float', optional: true, default: 0 }, 20 | Timestamp: { type: 'int', optional: true, default: 0 }, 21 | } 22 | }; 23 | const AccountAuthSchema = { 24 | name: 'AccountAuth', 25 | properties: { 26 | AccountNumber: { type: 'string', indexed: true, optional: true, default: '' }, 27 | Password: { type: 'string', optional: true, default: '' }, 28 | Timestamp: { type: 'int', optional: true, default: '' }, 29 | } 30 | }; 31 | const AccountTokenSchema = { 32 | name: 'AccountToken', 33 | properties: { 34 | Token: { type: 'string', optional: true, default: '' }, 35 | Timestamp: { type: 'int', optional: true, default: '' }, 36 | } 37 | }; 38 | const DeviceTokenSchema = { 39 | name: 'DeviceToken', 40 | properties: { 41 | Token: { type: 'string', optional: true, default: '' }, 42 | Platform: { type: 'string', optional: true, default: '' } 43 | } 44 | }; 45 | const AccountMetaSchema = { 46 | name: 'AccountMeta', 47 | properties: { 48 | AccountHolderGivenName: { type: 'string', optional: true, default: '' }, 49 | AccountHolderFamilyName: { type: 'string', optional: true, default: '' }, 50 | AccountHolderDateOfBirth: { type: 'string', optional: true, default: '' }, 51 | AccountHolderIdentificationNumber: { type: 'string', optional: true, default: '' }, 52 | AccountHolderContactNumber1: { type: 'string', optional: true, default: '' }, 53 | AccountHolderContactNumber2: { type: 'string', optional: true, default: '' }, 54 | AccountHolderEmailAddress: { type: 'string', optional: true, default: '' }, 55 | AccountHolderAddressLine1: { type: 'string', optional: true, default: '' }, 56 | AccountHolderAddressLine2: { type: 'string', optional: true, default: '' }, 57 | AccountHolderAddressLine3: { type: 'string', optional: true, default: '' }, 58 | AccountHolderPostalCode: { type: 'string', optional: true, default: '' }, 59 | } 60 | }; 61 | const TransactionsSchema = { 62 | name: 'Transactions', 63 | primaryKey: 'Transaction', 64 | properties: { 65 | Transaction: { type: 'int', indexed: true }, 66 | Type: { type: 'int', optional: true, default: '' }, 67 | SenderAccountNumber: { type: 'string', optional: true, default: '' }, 68 | SenderBankNumber: { type: 'string', optional: true, default: '' }, 69 | ReceiverAccountNumber: { type: 'string', optional: true, default: '' }, 70 | ReceiverBankNumber: { type: 'string', optional: true, default: '' }, 71 | TransactionAmount: 'float', 72 | SenderName: { type: 'string', optional: true, default: '' }, 73 | ReceiverName: { type: 'string', optional: true, default: '' }, 74 | FeeAmount: { type: 'float', optional: true, default: '' }, 75 | Lat: { type: 'float', optional: true, default: 0 }, 76 | Lon: { type: 'float', optional: true, default: 0 }, 77 | Desc: { type: 'string', optional: true, default: '' }, 78 | Status: { type: 'string', optional: true, default: '' }, 79 | Timestamp: { type: 'int', optional: true, default: 0 }, 80 | } 81 | }; 82 | const ContactsSchema = { 83 | name: 'Contacts', 84 | properties: { 85 | ContactName: { type: 'string', indexed: true, optional: true, default: '' }, 86 | ContactAccountNumber: { type: 'string', optional: true, default: '' }, 87 | ContactBankNumber: { type: 'string', optional: true, default: '' }, 88 | ContactEmailAddress: { type: 'string', optional: true, default: '' }, 89 | } 90 | }; 91 | 92 | let realm = new Realm({ schema: [ AccountSchema, AccountMetaSchema, AccountAuthSchema, AccountTokenSchema, DeviceTokenSchema, TransactionsSchema, ContactsSchema ], schemaVersion: 20 }); 93 | 94 | module.exports = realm; 95 | -------------------------------------------------------------------------------- /android/app/react.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.taskdefs.condition.Os 2 | 3 | def config = project.hasProperty("react") ? project.react : []; 4 | 5 | def bundleAssetName = config.bundleAssetName ?: "index.android.bundle" 6 | def entryFile = config.entryFile ?: "index.android.js" 7 | 8 | // because elvis operator 9 | def elvisFile(thing) { 10 | return thing ? file(thing) : null; 11 | } 12 | 13 | def reactRoot = elvisFile(config.root) ?: file("../../") 14 | def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"] 15 | 16 | void runBefore(String dependentTaskName, Task task) { 17 | Task dependentTask = tasks.findByPath(dependentTaskName); 18 | if (dependentTask != null) { 19 | dependentTask.dependsOn task 20 | } 21 | } 22 | 23 | gradle.projectsEvaluated { 24 | // Grab all build types and product flavors 25 | def buildTypes = android.buildTypes.collect { type -> type.name } 26 | def productFlavors = android.productFlavors.collect { flavor -> flavor.name } 27 | 28 | // When no product flavors defined, use empty 29 | if (!productFlavors) productFlavors.add('') 30 | 31 | productFlavors.each { productFlavorName -> 32 | buildTypes.each { buildTypeName -> 33 | // Create variant and target names 34 | def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}" 35 | def targetPath = productFlavorName ? 36 | "${productFlavorName}/${buildTypeName}" : 37 | "${buildTypeName}" 38 | 39 | // React js bundle directories 40 | def jsBundleDirConfigName = "jsBundleDir${targetName}" 41 | def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?: 42 | file("$buildDir/intermediates/assets/${targetPath}") 43 | 44 | def resourcesDirConfigName = "resourcesDir${targetName}" 45 | def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?: 46 | file("$buildDir/intermediates/res/merged/${targetPath}") 47 | def jsBundleFile = file("$jsBundleDir/$bundleAssetName") 48 | 49 | // Bundle task name for variant 50 | def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets" 51 | 52 | def currentBundleTask = tasks.create( 53 | name: bundleJsAndAssetsTaskName, 54 | type: Exec) { 55 | group = "react" 56 | description = "bundle JS and assets for ${targetName}." 57 | 58 | // Create dirs if they are not there (e.g. the "clean" task just ran) 59 | doFirst { 60 | jsBundleDir.mkdirs() 61 | resourcesDir.mkdirs() 62 | } 63 | 64 | // Set up inputs and outputs so gradle can cache the result 65 | inputs.files fileTree(dir: reactRoot, excludes: inputExcludes) 66 | outputs.dir jsBundleDir 67 | outputs.dir resourcesDir 68 | 69 | // Set up the call to the react-native cli 70 | workingDir reactRoot 71 | 72 | // Set up dev mode 73 | def devEnabled = !targetName.toLowerCase().contains("release") 74 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 75 | commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}", 76 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir 77 | } else { 78 | commandLine "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}", 79 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir 80 | } 81 | 82 | enabled config."bundleIn${targetName}" || 83 | config."bundleIn${buildTypeName.capitalize()}" ?: 84 | targetName.toLowerCase().contains("release") 85 | } 86 | 87 | // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process 88 | currentBundleTask.dependsOn("merge${targetName}Resources") 89 | currentBundleTask.dependsOn("merge${targetName}Assets") 90 | 91 | runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask) 92 | runBefore("processX86${targetName}Resources", currentBundleTask) 93 | runBefore("processUniversal${targetName}Resources", currentBundleTask) 94 | runBefore("process${targetName}Resources", currentBundleTask) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ios/BVNK.xcodeproj/xcshareddata/xcschemes/BVNK.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /ios/BVNK.xcodeproj/xcshareddata/xcschemes/BankReact.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /MainPaymentDepositView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | Image, 12 | TouchableOpacity, 13 | Alert 14 | } from 'react-native'; 15 | 16 | import Button from 'react-native-button' 17 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 18 | 19 | let styles = require('./styles'); 20 | let BankClient = require('./libs/BankClient'); 21 | let bc = new BankClient(); 22 | let db = require('./libs/RealmDB'); 23 | let dismissKeyboard = require('dismissKeyboard'); 24 | 25 | var MainPaymentDepositView = React.createClass({ 26 | getInitialState() { 27 | dismissKeyboard(); 28 | return { 29 | depositAmount: '', 30 | depositDesc: '', 31 | initialPosition: 'unknown', 32 | lastPosition: 'unknown', 33 | } 34 | }, 35 | 36 | componentDidMount: function() { 37 | navigator.geolocation.getCurrentPosition( 38 | (position) => { 39 | var initialPosition = JSON.stringify(position); 40 | this.setState({initialPosition}); 41 | }, 42 | (error) => console.log(error.message), 43 | {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000} 44 | ); 45 | 46 | this.watchID = navigator.geolocation.watchPosition((position) => { 47 | var lastPosition = JSON.stringify(position); this.setState({lastPosition}); 48 | }); 49 | }, 50 | 51 | componentWillUnmount: function() { 52 | navigator.geolocation.clearWatch(this.watchID); 53 | }, 54 | 55 | _doDeposit: function() { 56 | let user = db.objects('Account'); 57 | if (user.length > 0) { 58 | var userAccount = user.slice(0,1); 59 | userAccount = userAccount[0]; 60 | var lat = 0; 61 | var lon = 0; 62 | let lastPosState = this.state.lastPosition; 63 | if (lastPosState != 'unknown') { 64 | let lastPos = JSON.parse(this.state.lastPosition); 65 | lat = lastPos.coords.latitude; 66 | lon = lastPos.coords.longitude; 67 | } 68 | // Replace , with . in payment amount 69 | let paymentAmount = this.state.depositAmount.replace(",", "."); 70 | let data = { 71 | AccountDetails: userAccount.AccountNumber+'@'+userAccount.BankNumber, 72 | Amount: paymentAmount, 73 | Lat: lat, 74 | Lon: lon, 75 | Desc: this.state.depositDesc 76 | }; 77 | 78 | let res = bc.paymentDeposit(data, function(res) { 79 | console.log(res); 80 | if (typeof res.error == 'undefined') { 81 | console.log('Go to main...'); 82 | dismissKeyboard(); 83 | Actions.main({ type: "reset", message: "🎉 Deposit successful"}); 84 | } else { 85 | // Show error 86 | dismissKeyboard(); 87 | Actions.main({ type : "reset", message: "❌ Error: "+res.error }); 88 | } 89 | }); 90 | } 91 | }, 92 | 93 | render: function() { 94 | return ( 95 | 96 | 97 | 98 | 99 | 100 | 101 | DEPOSIT PAYMENT 102 | this.setState({depositAmount})} 105 | value={this.state.depositAmount} 106 | autoCorrect={false} 107 | autoCapitalize="none" 108 | keyboardType='decimal-pad' 109 | placeholder="Deposit Amount" 110 | /> 111 | this.setState({depositDesc})} 114 | value={this.state.depositDesc} 115 | autoCorrect={false} 116 | placeholder="Description" 117 | /> 118 | 120 | 121 | 122 | 123 | ) 124 | } 125 | }); 126 | 127 | module.exports = MainPaymentDepositView; 128 | -------------------------------------------------------------------------------- /MainPaymentCreditView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | Image, 12 | TouchableOpacity, 13 | Alert 14 | } from 'react-native'; 15 | 16 | import Button from 'react-native-button' 17 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 18 | 19 | let styles = require('./styles'); 20 | let BankClient = require('./libs/BankClient'); 21 | let bc = new BankClient(); 22 | let db = require('./libs/RealmDB'); 23 | let dismissKeyboard = require('dismissKeyboard'); 24 | 25 | var MainPaymentCreditView = React.createClass({ 26 | getInitialState() { 27 | dismissKeyboard(); 28 | return { 29 | paymentAmount: '', 30 | paymentDesc: '', 31 | initialPosition: 'unknown', 32 | lastPosition: 'unknown', 33 | } 34 | }, 35 | 36 | componentDidMount: function() { 37 | navigator.geolocation.getCurrentPosition( 38 | (position) => { 39 | var initialPosition = JSON.stringify(position); 40 | this.setState({initialPosition}); 41 | }, 42 | (error) => console.log(error.message), 43 | {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000} 44 | ); 45 | 46 | this.watchID = navigator.geolocation.watchPosition((position) => { 47 | var lastPosition = JSON.stringify(position); this.setState({lastPosition}); 48 | }); 49 | }, 50 | 51 | componentWillUnmount: function() { 52 | navigator.geolocation.clearWatch(this.watchID); 53 | }, 54 | 55 | _doPayment: function() { 56 | let user = db.objects('Account'); 57 | if (user.length > 0) { 58 | var userAccount = user.slice(0,1); 59 | userAccount = userAccount[0]; 60 | var lat = 0; 61 | var lon = 0; 62 | let lastPosState = this.state.lastPosition; 63 | if (lastPosState != 'unknown') { 64 | let lastPos = JSON.parse(this.state.lastPosition); 65 | lat = lastPos.coords.latitude; 66 | lon = lastPos.coords.longitude; 67 | } 68 | // Replace , with . in payment amount 69 | let paymentAmount = this.state.paymentAmount.replace(",", "."); 70 | let data = { 71 | SenderDetails: userAccount.AccountNumber+'@'+userAccount.BankNumber, 72 | RecipientDetails: this.props.data.ContactAccountNumber+'@'+this.props.data.ContactBankNumber, 73 | Amount: paymentAmount, 74 | Lat: lat, 75 | Lon: lon, 76 | Desc: this.state.paymentDesc 77 | }; 78 | 79 | let res = bc.paymentCredit(data, function(res) { 80 | console.log(res); 81 | if (typeof res.error == 'undefined') { 82 | dismissKeyboard(); 83 | Actions.main({ type : "reset", message: "💸 Payment successful" }); 84 | } else { 85 | // Show error 86 | Actions.main({ type : "reset", message: "❌ Error: "+res.error }); 87 | dismissKeyboard(); 88 | return; 89 | } 90 | }); 91 | } 92 | }, 93 | 94 | render: function() { 95 | return ( 96 | 97 | 98 | 99 | 100 | 101 | 102 | CREDIT PAYMENT 103 | Make payment to: {this.props.data.ContactName} 104 | this.setState({paymentAmount})} 107 | value={this.state.paymentAmount} 108 | autoCorrect={false} 109 | keyboardType='decimal-pad' 110 | autoCapitalize="none" 111 | placeholder="Payment Amount" 112 | /> 113 | this.setState({paymentDesc})} 116 | value={this.state.paymentDesc} 117 | autoCorrect={false} 118 | placeholder="Description" 119 | /> 120 | 122 | 123 | 124 | 125 | ) 126 | } 127 | }); 128 | 129 | module.exports = MainPaymentCreditView; 130 | -------------------------------------------------------------------------------- /AddContactView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { 4 | AppRegistry, 5 | Text, 6 | View, 7 | StatusBar, 8 | StyleSheet, 9 | TextInput, 10 | Image, 11 | TouchableOpacity, 12 | ListView, 13 | Alert 14 | } from 'react-native'; 15 | 16 | import React, { Component } from 'react'; 17 | 18 | import Button from 'react-native-button' 19 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 20 | 21 | let styles = require('./styles'); 22 | let BankClient = require('./libs/BankClient'); 23 | let bc = new BankClient(); 24 | let db = require('./libs/RealmDB'); 25 | let dismissKeyboard = require('dismissKeyboard'); 26 | 27 | var AddContactView = React.createClass({ 28 | getInitialState() { 29 | dismissKeyboard(); 30 | let contacts = []; 31 | var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); 32 | return { 33 | search: '', 34 | message: '', 35 | dataSource: ds.cloneWithRows(contacts), 36 | } 37 | }, 38 | 39 | componentDidMount: function() { 40 | }, 41 | 42 | componentWillUnmount: function() { 43 | }, 44 | 45 | _doSearch: function() { 46 | let data = { 47 | Search: this.state.search, 48 | }; 49 | 50 | var self = this; 51 | let res = bc.accountSearch(data, function(res) { 52 | console.log(res); 53 | if (typeof res.error == 'undefined') { 54 | if (res.response.length == 0) { 55 | self.setState({ 'message' : 'No contacts found' }); 56 | self.setState({ 57 | dataSource: self.state.dataSource.cloneWithRows([]) 58 | }) 59 | return; 60 | } 61 | self.setState({ 'message' : '' }); 62 | var newDs = res.response; 63 | self.setState({ 64 | dataSource: self.state.dataSource.cloneWithRows(newDs) 65 | }) 66 | dismissKeyboard(); 67 | } else { 68 | // Show error 69 | self.setState({ 'message' : res.error }); 70 | dismissKeyboard(); 71 | return; 72 | } 73 | }); 74 | }, 75 | 76 | addContact: function(data) { 77 | db.write(() => { 78 | // Check if contact exists 79 | var contactDB = db.objects('Contacts').filtered('ContactName == $0 && ContactAccountNumber == $1 && ContactBankNumber == $2', (data.FamilyName + ',' + data.GivenName), data.AccountNumber, data.BankNumber); 80 | 81 | if (contactDB.length == 0) { 82 | db.create('Contacts', { ContactName: (data.FamilyName+','+data.GivenName), ContactAccountNumber: data.AccountNumber, ContactBankNumber: data.BankNumber, ContactEmailAddress: data.EmailAddress }); 83 | // Fetch contact 84 | contactDB = db.objects('Contacts').filtered('ContactName == $0 && ContactAccountNumber == $1 && ContactBankNumber == $2', (data.FamilyName + ',' + data.GivenName), data.AccountNumber, data.BankNumber); 85 | }; 86 | 87 | Actions.contact({data: contactDB[0], type: 'reset'}); 88 | return; 89 | }); 90 | }, 91 | 92 | render: function() { 93 | var notificationMessage; 94 | if (this.state.message != '') { 95 | notificationMessage = {this.state.message}; 96 | } 97 | 98 | return ( 99 | 100 | 101 | 102 | 103 | 104 | 105 | CONTACT SEARCH 106 | this.setState({search})} 109 | value={this.state.search} 110 | autoCorrect={false} 111 | placeholder="Email, ID or Name" 112 | /> 113 | 115 | {notificationMessage} 116 | 117 | 121 | 123 | this.addContact(rowData)} 124 | style={styles.global.contactItemText}>{rowData.FamilyName}, {rowData.GivenName} 125 | } 126 | /> 127 | 128 | 129 | 130 | ) 131 | } 132 | }); 133 | 134 | module.exports = AddContactView; 135 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // the root of your project, i.e. where "package.json" lives 37 | * root: "../../", 38 | * 39 | * // where to put the JS bundle asset in debug mode 40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 41 | * 42 | * // where to put the JS bundle asset in release mode 43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 44 | * 45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 46 | * // require('./image.png')), in debug mode 47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 48 | * 49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 50 | * // require('./image.png')), in release mode 51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 52 | * 53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 57 | * // for example, you might want to remove it from here. 58 | * inputExcludes: ["android/**", "ios/**"] 59 | * ] 60 | */ 61 | 62 | apply from: "react.gradle" 63 | 64 | /** 65 | * Set this to true to create two separate APKs instead of one: 66 | * - An APK that only works on ARM devices 67 | * - An APK that only works on x86 devices 68 | * The advantage is the size of the APK is reduced by about 4MB. 69 | * Upload all the APKs to the Play Store and people will download 70 | * the correct one based on the CPU architecture of their device. 71 | */ 72 | def enableSeparateBuildPerCPUArchitecture = false 73 | 74 | /** 75 | * Run Proguard to shrink the Java bytecode in release builds. 76 | */ 77 | def enableProguardInReleaseBuilds = false 78 | 79 | android { 80 | compileSdkVersion 23 81 | buildToolsVersion "23.0.1" 82 | 83 | defaultConfig { 84 | applicationId "com.bvnk" 85 | minSdkVersion 16 86 | targetSdkVersion 22 87 | versionCode 1 88 | versionName "1.0" 89 | ndk { 90 | abiFilters "armeabi-v7a", "x86" 91 | } 92 | } 93 | splits { 94 | abi { 95 | reset() 96 | enable enableSeparateBuildPerCPUArchitecture 97 | universalApk false // If true, also generate a universal APK 98 | include "armeabi-v7a", "x86" 99 | } 100 | } 101 | buildTypes { 102 | release { 103 | minifyEnabled enableProguardInReleaseBuilds 104 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 105 | } 106 | } 107 | // applicationVariants are e.g. debug, release 108 | applicationVariants.all { variant -> 109 | variant.outputs.each { output -> 110 | // For each separate APK per architecture, set a unique version code as described here: 111 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 112 | def versionCodes = ["armeabi-v7a":1, "x86":2] 113 | def abi = output.getFilter(OutputFile.ABI) 114 | if (abi != null) { // null for the universal-debug, universal-release variants 115 | output.versionCodeOverride = 116 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 117 | } 118 | } 119 | } 120 | } 121 | 122 | dependencies { 123 | compile project(':react-native-push-notification') 124 | compile project(':react-native-maps') 125 | compile project(':realm') 126 | compile fileTree(dir: "libs", include: ["*.jar"]) 127 | compile "com.android.support:appcompat-v7:23.0.1" 128 | compile "com.facebook.react:react-native:+" // From node_modules 129 | } 130 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /CreateAuthView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | Image, 12 | Alert 13 | } from 'react-native'; 14 | 15 | import Button from 'react-native-button' 16 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 17 | 18 | let styles = require('./styles'); 19 | let BankClient = require('./libs/BankClient'); 20 | let bc = new BankClient(); 21 | let db = require('./libs/RealmDB'); 22 | let dismissKeyboard = require('dismissKeyboard'); 23 | 24 | var CreateAuthView = React.createClass({ 25 | getInitialState() { 26 | dismissKeyboard(); 27 | return { 28 | password: '' 29 | } 30 | }, 31 | 32 | doLogin: function() { 33 | console.log('Do login called'); 34 | let userAuth = db.objects('AccountAuth'); 35 | if (userAuth.length > 0) { 36 | var userAccount = userAuth.slice(0,1); 37 | userAccount = userAccount[0]; 38 | 39 | let data = { User: userAccount.AccountNumber, Password: userAccount.Password }; 40 | let res = bc.authLogin(data, function(res) { 41 | if (typeof res.error == 'undefined') { 42 | console.log(res); 43 | console.log(res.response); 44 | // Get token 45 | let token = res.response; 46 | db.write(() => { 47 | // Delete tokens 48 | let allTokens = db.objects('AccountToken'); 49 | db.delete(allTokens); 50 | 51 | db.create('AccountToken', { 52 | Token: token, 53 | //Timestamp: Math.floor(Date.now()) 54 | Timestamp: 1 55 | }); 56 | }); 57 | // Go to account landing view 58 | dismissKeyboard(); 59 | Actions.main({type : "reset"}); 60 | } else { 61 | // Show error 62 | Alert.alert('Error', res.error); 63 | dismissKeyboard(); 64 | return; 65 | } 66 | }); 67 | } 68 | }, 69 | 70 | _doCreateAuth: function() { 71 | //Alert.alert('Password', this.state.password); 72 | // Get user account number 73 | let user = db.objects('Account'); 74 | // Check if there is a result 75 | if (user.length > 0) 76 | { 77 | // Get first user account 78 | var userAccount = user.slice(0,1); 79 | userAccount = userAccount[0]; 80 | let data = {User: userAccount.AccountNumber, Password: this.state.password}; 81 | let res = bc.authCreate(data, this.authCreateCallback); 82 | } 83 | }, 84 | 85 | authCreateCallback: function(res) { 86 | let user = db.objects('Account'); 87 | // Check if there is a result 88 | if (user.length > 0) 89 | { 90 | // Get first user account 91 | var userAccount = user.slice(0,1); 92 | userAccount = userAccount[0]; 93 | let data = {User: userAccount.AccountNumber, Password: this.state.password}; 94 | console.log(res); 95 | if (typeof res.error == 'undefined') { 96 | console.log('before insert'); 97 | // Save account auth details 98 | db.write(() => { 99 | let auth = db.objects('AccountAuth'); 100 | db.delete(auth); 101 | 102 | db.create('AccountAuth', { 103 | AccountNumber: data.User, 104 | Password: data.Password, 105 | //Timestamp: Math.floor(Date.now()) 106 | Timestamp: 1 107 | }); 108 | }); 109 | // Log user in 110 | console.log('after insert'); 111 | this.doLogin(); 112 | } else if (res.error == 'appauth.CreateUserPassword: Account already exists'){ 113 | // Log user in 114 | console.log('at error, show login'); 115 | this.doLogin(); 116 | } else { 117 | // Show error 118 | Alert.alert('Error', res.error); 119 | return; 120 | } 121 | } 122 | }, 123 | 124 | render: function() { 125 | return ( 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | this.setState({password})} 136 | value={this.state.password} 137 | autoCorrect={false} 138 | keyboardAppearance="dark" 139 | autoCapitalize="none" 140 | secureTextEntry={true} 141 | placeholder="Password" 142 | /> 143 | 145 | 146 | 147 | 148 | 149 | ) 150 | } 151 | }); 152 | 153 | module.exports = CreateAuthView; 154 | -------------------------------------------------------------------------------- /MainTransactionsView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | ListView, 12 | Image, 13 | TouchableOpacity, 14 | Alert 15 | } from 'react-native'; 16 | 17 | import Button from 'react-native-button' 18 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 19 | 20 | let styles = require('./styles'); 21 | let BankClient = require('./libs/BankClient'); 22 | let bc = new BankClient(); 23 | let db = require('./libs/RealmDB'); 24 | let dismissKeyboard = require('dismissKeyboard'); 25 | 26 | var MainTransactionsView = React.createClass({ 27 | 28 | getInitialState: function() { 29 | dismissKeyboard(); 30 | // Limit to 100 transactions 31 | let transactions = db.objects('Transactions').sorted('Timestamp', 'reverse').slice(0, 100); 32 | var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); 33 | return { 34 | dataSource: ds.cloneWithRows(transactions), 35 | }; 36 | }, 37 | 38 | timeConverter: function(UNIX_timestamp) { 39 | var a = new Date(UNIX_timestamp * 1000); 40 | var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; 41 | var year = a.getFullYear(); 42 | var month = months[a.getMonth()]; 43 | var date = a.getDate(); 44 | var hour = a.getHours(); 45 | var min = a.getMinutes(); 46 | var sec = a.getSeconds(); 47 | var time = date + ' ' + month + ' ' + year + ' ' + hour + ':' + min + ':' + sec ; 48 | return time; 49 | }, 50 | 51 | 52 | componentDidMount: function() { 53 | // Get latest transactions 54 | let transactionsRes = db.objects('Transactions'); 55 | var transactionsResSorted = transactionsRes.sorted('Timestamp'); 56 | var timestamp = 0 57 | if (transactionsResSorted.length > 0) { 58 | // Get latest 59 | let latestTransaction = transactionsResSorted.slice(transactionsResSorted.length - 1, transactionsResSorted.length); 60 | if (latestTransaction.length > 0) { 61 | timestamp = latestTransaction[0].Timestamp; 62 | } 63 | } 64 | 65 | // We set up the data to fetch 20 records 66 | // @TODO implement pagination/inifinte scrolling 67 | let data = { 68 | perPage : 20, 69 | page : 0, 70 | timestamp : timestamp 71 | }; 72 | 73 | let res = bc.transactionsListAfterTimestamp(data, function(res) { 74 | if (typeof res.error == 'undefined') { 75 | let transactionList = res.response; 76 | db.write(() => { 77 | transactionList.forEach(function(t) { 78 | // Check if transaction exists 79 | let trDB = db.objects('Transactions').filtered('Transaction == $0', t.ID); 80 | 81 | if (trDB.length == 0) { 82 | var senderName = ""; 83 | var receiverName = ""; 84 | 85 | var contact = db.objects('Contacts').filtered('ContactAccountNumber == $0 && ContactBankNumber == $1', t.Receiver.AccountNumber, t.Receiver.BankNumber); 86 | if (contact.length > 0) { 87 | receiverName = contact[0].ContactName; 88 | } 89 | 90 | contact = db.objects('Contacts').filtered('ContactAccountNumber == $0 && ContactBankNumber == $1', t.Sender.AccountNumber, t.Sender.BankNumber); 91 | if (contact.length > 0) { 92 | senderName = contact[0].ContactName; 93 | } 94 | db.create('Transactions', { 95 | Transaction: t.ID, 96 | Type: t.PainType, 97 | SenderAccountNumber: t.Sender.AccountNumber, 98 | SenderBankNumber: t.Sender.BankNumber, 99 | ReceiverAccountNumber: t.Receiver.AccountNumber, 100 | ReceiverBankNumber: t.Receiver.BankNumber, 101 | TransactionAmount: t.Amount, 102 | FeeAmount: t.Fee, 103 | Lat: t.Geo[0], 104 | Lon: t.Geo[1], 105 | Desc: t.Desc, 106 | Status: t.Status, 107 | Timestamp: t.Timestamp, 108 | }); 109 | } 110 | }); 111 | }); 112 | } else { 113 | Alert.alert('Error', 'Could not update account details: '+res.error); 114 | console.log(res); 115 | dismissKeyboard(); 116 | return; 117 | } 118 | }); 119 | }, 120 | 121 | render: function() { 122 | return ( 123 | 124 | 125 | 126 | 127 | 128 | 129 | TRANSACTIONS 130 | 134 | 136 | Actions.transaction({ data: rowData })} style={styles.transaction.desc}>{rowData.Desc} 137 | Actions.transaction({ data: rowData })} style={styles.transaction.time}>{this.timeConverter(rowData.Timestamp)} 138 | } 139 | /> 140 | 141 | 142 | 143 | ) 144 | } 145 | }); 146 | 147 | module.exports = MainTransactionsView; 148 | -------------------------------------------------------------------------------- /TransactionView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | Image, 12 | Alert 13 | } from 'react-native'; 14 | 15 | import Button from 'react-native-button' 16 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 17 | import MapView from 'react-native-maps'; 18 | 19 | let styles = require('./styles'); 20 | let BankClient = require('./libs/BankClient'); 21 | let bc = new BankClient(); 22 | let db = require('./libs/RealmDB'); 23 | let dismissKeyboard = require('dismissKeyboard'); 24 | 25 | var TransactionView = React.createClass({ 26 | getInitialState() { 27 | dismissKeyboard(); 28 | return { 29 | data: { }, 30 | transaction: { }, 31 | } 32 | }, 33 | 34 | timeConverter: function(UNIX_timestamp) { 35 | var a = new Date(UNIX_timestamp * 1000); 36 | var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; 37 | var year = a.getFullYear(); 38 | var month = months[a.getMonth()]; 39 | var date = a.getDate(); 40 | var hour = a.getHours(); 41 | var min = a.getMinutes(); 42 | var sec = a.getSeconds(); 43 | var time = date + ' ' + month + ' ' + year + ' ' + hour + ':' + min + ':' + sec ; 44 | return time; 45 | }, 46 | 47 | checkTransactionDetails: function() { 48 | db.write(() => { 49 | // Check if transaction exists 50 | let trDB = db.objects('Transactions').filtered('Transaction == $0', this.props.data.Transaction); 51 | console.log("Check length of transaction"); 52 | console.log(trDB.length); 53 | console.log(this.props.data); 54 | 55 | if ((trDB.length == 1) && (this.props.data.ReceiverName == "") && (this.props.data.SenderName == "")) { 56 | let transaction = trDB[0]; 57 | var senderName = ""; 58 | var receiverName = ""; 59 | 60 | var contact = db.objects('Contacts').filtered('ContactAccountNumber == $0 && ContactBankNumber == $1', transaction.ReceiverAccountNumber, transaction.ReceiverBankNumber); 61 | if (contact.length > 0) { 62 | receiverName = contact[0].ContactName; 63 | } 64 | 65 | contact = db.objects('Contacts').filtered('ContactAccountNumber == $0 && ContactBankNumber == $1', transaction.SenderAccountNumber, transaction.SenderBankNumber); 66 | if (contact.length > 0) { 67 | senderName = contact[0].ContactName; 68 | } 69 | 70 | db.create('Transactions', { 71 | Transaction: transaction.Transaction, 72 | Type: transaction.Type, 73 | SenderAccountNumber: transaction.SenderAccountNumber, 74 | SenderBankNumber: transaction.SenderBankNumber, 75 | ReceiverAccountNumber: transaction.ReceiverAccountNumber, 76 | ReceiverBankNumber: transaction.ReceiverBankNumber, 77 | TransactionAmount: transaction.TransactionAmount, 78 | SenderName: senderName, 79 | ReceiverName: receiverName, 80 | FeeAmount: transaction.FeeAmount, 81 | Lat: transaction.Lat, 82 | Lon: transaction.Lon, 83 | Desc: transaction.Desc, 84 | Status: transaction.Status, 85 | Timestamp: transaction.Timestamp, 86 | }, true); 87 | } 88 | }); 89 | }, 90 | 91 | updateStateListener: function() { 92 | let id = parseInt(this.props.data.Transaction); 93 | let trDB = db.objects('Transactions').filtered('Transaction == $0', id); 94 | var transArr = trDB.slice(0,1); 95 | let transaction = transArr[0]; 96 | this.setState({ 'transaction' : transaction }); 97 | }, 98 | 99 | componentDidMount: function() { 100 | // Update transaction list 101 | this.checkTransactionDetails(); 102 | this.updateStateListener(); 103 | // Observe Realm Change Events 104 | db.addListener('change', this.updateStateListener); 105 | }, 106 | 107 | componentWillUnmount: function() { 108 | // Remove the listener 109 | db.removeListener('change', this.updateStateListener); 110 | }, 111 | 112 | render: function() { 113 | 114 | let marker = { latitude: this.props.data.Lat, longitude: this.props.data.Lon }; 115 | //let marker = { latitude: 37.7749, longitude: -122.4194 }; 116 | console.log(marker); 117 | 118 | return ( 119 | 120 | 121 | 122 | 123 | 124 | 125 | 136 | 141 | 142 | Sender: {this.props.data.SenderName} 143 | Receipient: {this.props.data.ReceiverName} 144 | {this.props.data.Desc} 145 | Amount: {this.props.data.TransactionAmount.toFixed(4)} 146 | Fee: {this.props.data.FeeAmount.toFixed(4)} 147 | {this.timeConverter(this.props.data.Timestamp)} 148 | 149 | 152 | 153 | 154 | 155 | ) 156 | } 157 | }); 158 | 159 | module.exports = TransactionView; 160 | -------------------------------------------------------------------------------- /RegisterView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | TextInput, 8 | View, 9 | StatusBar, 10 | StyleSheet, 11 | Image, 12 | Alert 13 | } from 'react-native'; 14 | 15 | import Button from 'react-native-button' 16 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 17 | 18 | var styles = require('./styles'); 19 | let BankClient = require('./libs/BankClient'); 20 | let bc = new BankClient(); 21 | let db = require('./libs/RealmDB'); 22 | let dismissKeyboard = require('dismissKeyboard'); 23 | 24 | var RegisterView = React.createClass({ 25 | getInitialState() { 26 | dismissKeyboard(); 27 | return { 28 | givenName: '', 29 | familyName: '', 30 | idNumber: '', 31 | email: '' 32 | } 33 | }, 34 | 35 | _doRegister: function() { 36 | let data = { 37 | AccountHolderGivenName: this.state.givenName, 38 | AccountHolderFamilyName: this.state.familyName, 39 | AccountHolderDateOfBirth: '', 40 | AccountHolderIdentificationNumber: this.state.idNumber, 41 | AccountHolderContactNumber1: '', 42 | AccountHolderContactNumber2: '', 43 | AccountHolderEmailAddress: this.state.email, 44 | AccountHolderAddressLine1: '', 45 | AccountHolderAddressLine2: '', 46 | AccountHolderAddressLine3: '', 47 | AccountHolderPostalCode: '', 48 | }; 49 | let res = bc.accountCreate(data, function(res) { 50 | console.log("At register"); 51 | console.log(res); 52 | console.log('One'); 53 | console.log(res.response); 54 | console.log('Two'); 55 | console.log(typeof res.response); 56 | console.log('Three'); 57 | if (typeof res.response != 'undefined') { 58 | let accountId = res.response; 59 | console.log('AccountID: '+accountId); 60 | // Set in DB 61 | db.write(() => { 62 | // Delete all other accounts for now 63 | let accounts = db.objects('Account'); 64 | db.delete(accounts); 65 | let contacts = db.objects('Contacts'); 66 | db.delete(contacts); 67 | let transactions = db.objects('Transactions'); 68 | db.delete(transactions); 69 | let auth = db.objects('AccountAuth'); 70 | db.delete(auth); 71 | let authToken = db.objects('AccountToken'); 72 | db.delete(authToken); 73 | let accountMeta = db.objects('AccountMeta'); 74 | db.delete(accountMeta); 75 | let deviceToken = db.objects('DeviceToken'); 76 | db.delete(deviceToken); 77 | 78 | db.create('Account', { 79 | AccountNumber: accountId, 80 | BankNumber: '', 81 | AccountHolderName: data.AccountHolderFamilyName+','+data.AccountHolderGivenName, 82 | AccountBalance: 0, 83 | Overdraft: 0, 84 | AvailableBalance: 0, 85 | //Timestamp: Math.floor(Date.now()) 86 | Timestamp: 1 87 | }); 88 | }); 89 | console.log('Written'); 90 | // Read the account value from DB 91 | let user = db.objects('Account'); 92 | let userAccount = user.filtered('AccountNumber == $0', accountId); 93 | console.log('User?'); 94 | console.log(userAccount); 95 | dismissKeyboard(); 96 | if (userAccount.length == 1) { 97 | console.log("Successfull") 98 | console.log(userAccount[0]); 99 | Actions.createAuth(); 100 | } 101 | // Alert token value 102 | // Load new page 103 | } else if (typeof res.error != 'undefined') { 104 | dismissKeyboard(); 105 | Alert.alert('Error', res.error); 106 | console.log('Error'); 107 | } 108 | }); 109 | }, 110 | 111 | render() { 112 | return ( 113 | 114 | 115 | 116 | 117 | 118 | this.setState({givenName})} 121 | value={this.state.givenName} 122 | autoCorrect={false} 123 | placeholder="Given Name" 124 | /> 125 | this.setState({familyName})} 128 | value={this.state.familyName} 129 | autoCorrect={false} 130 | placeholder="Family Name" 131 | /> 132 | this.setState({idNumber})} 135 | value={this.state.idNumber} 136 | autoCorrect={false} 137 | keyboardType='number-pad' 138 | placeholder="ID Number" 139 | /> 140 | this.setState({email})} 143 | value={this.state.email} 144 | autoCorrect={false} 145 | autoCapitalize="none" 146 | keyboardType='email-address' 147 | placeholder="Email" 148 | /> 149 | 151 | 152 | 153 | ) 154 | } 155 | }); 156 | 157 | module.exports = RegisterView; 158 | -------------------------------------------------------------------------------- /FetchAccountView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | Image, 12 | Alert 13 | } from 'react-native'; 14 | 15 | import Button from 'react-native-button' 16 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 17 | 18 | let styles = require('./styles'); 19 | let BankClient = require('./libs/BankClient'); 20 | let bc = new BankClient(); 21 | let db = require('./libs/RealmDB'); 22 | let dismissKeyboard = require('dismissKeyboard'); 23 | 24 | var FetchAccountView = React.createClass({ 25 | getInitialState() { 26 | dismissKeyboard(); 27 | return { 28 | givenName: '', 29 | familyName: '', 30 | idNumber: '', 31 | email: '' 32 | } 33 | }, 34 | 35 | _doFetchAccount: function() { 36 | let data = { 37 | AccountHolderGivenName: this.state.givenName, 38 | AccountHolderFamilyName: this.state.familyName, 39 | AccountHolderDateOfBirth: '', 40 | AccountHolderIdentificationNumber: this.state.idNumber, 41 | AccountHolderContactNumber1: '', 42 | AccountHolderContactNumber2: '', 43 | AccountHolderEmailAddress: this.state.email, 44 | AccountHolderAddressLine1: '', 45 | AccountHolderAddressLine2: '', 46 | AccountHolderAddressLine3: '', 47 | AccountHolderPostalCode: '', 48 | }; 49 | let res = bc.fetchAccount(data, function(res) { 50 | if (typeof res.response != 'undefined') { 51 | let accountId = res.response; 52 | if (accountId == "") { 53 | // Account not found 54 | alert("Account not found"); 55 | } 56 | console.log('AccountID: '+accountId); 57 | // Set in DB 58 | db.write(() => { 59 | // Delete all other accounts for now 60 | let accounts = db.objects('Account'); 61 | db.delete(accounts); 62 | let contacts = db.objects('Contacts'); 63 | db.delete(contacts); 64 | let transactions = db.objects('Transactions'); 65 | db.delete(transactions); 66 | let auth = db.objects('AccountAuth'); 67 | db.delete(auth); 68 | let authToken = db.objects('AccountToken'); 69 | db.delete(authToken); 70 | let accountMeta = db.objects('AccountMeta'); 71 | db.delete(accountMeta); 72 | let deviceToken = db.objects('DeviceToken'); 73 | db.delete(deviceToken); 74 | 75 | db.create('Account', { 76 | AccountNumber: accountId, 77 | BankNumber: '', 78 | AccountHolderName: data.AccountHolderFamilyName+','+data.AccountHolderGivenName, 79 | AccountBalance: 0, 80 | Overdraft: 0, 81 | AvailableBalance: 0, 82 | //Timestamp: Math.floor(Date.now()) 83 | Timestamp: 1 84 | }); 85 | }); 86 | 87 | // Read the account value from DB 88 | let user = db.objects('Account'); 89 | let userAccount = user.filtered('AccountNumber == $0', accountId); 90 | console.log('User?'); 91 | console.log(userAccount); 92 | dismissKeyboard(); 93 | if (userAccount.length == 1) { 94 | console.log("Successfull") 95 | console.log(userAccount[0]); 96 | Actions.login(); 97 | } 98 | // Alert token value 99 | // Load new page 100 | } else if (typeof res.error != 'undefined') { 101 | dismissKeyboard(); 102 | Alert.alert('Error', res.error); 103 | console.log('Error'); 104 | } 105 | }); 106 | }, 107 | 108 | render: function() { 109 | return ( 110 | 111 | 112 | 113 | 114 | 115 | 116 | this.setState({givenName})} 119 | value={this.state.givenName} 120 | autoCorrect={false} 121 | placeholder="Given Name" 122 | /> 123 | this.setState({familyName})} 126 | value={this.state.familyName} 127 | autoCorrect={false} 128 | placeholder="Family Name" 129 | /> 130 | this.setState({idNumber})} 133 | value={this.state.idNumber} 134 | autoCorrect={false} 135 | keyboardType='number-pad' 136 | placeholder="ID Number" 137 | /> 138 | this.setState({email})} 141 | value={this.state.email} 142 | autoCorrect={false} 143 | autoCapitalize="none" 144 | keyboardType='email-address' 145 | placeholder="Email" 146 | /> 147 | 149 | 151 | 152 | 153 | 154 | ) 155 | } 156 | }); 157 | 158 | module.exports = FetchAccountView; 159 | -------------------------------------------------------------------------------- /libs/BankClient.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { 4 | AppRegistry, 5 | Component, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | Alert 12 | } from 'react-native'; 13 | 14 | let db = require('./RealmDB'); 15 | import {Scene, Router, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 16 | 17 | // @TODO Local testing 18 | const url = 'https://bvnk.co:8443'; 19 | //const url = 'https://bvnk.co:8443/'; 20 | 21 | //var BankClient = React.createClass({ 22 | function BankClient() { 23 | 24 | this._doCallNoAuthGet = function(route, method, callback) { 25 | console.log('Route: noauth get :'+url+route); 26 | fetch(url+route, { 27 | method: method, 28 | headers: { 29 | 'Accept': 'application/json', 30 | 'Content-Type': 'application/json', 31 | }, 32 | }) 33 | .then((response) => response.json()) 34 | .then((responseText) => { 35 | console.log('Called: '+route); 36 | callback(responseText); 37 | }) 38 | .catch((error) => { 39 | callback(error); 40 | }); 41 | }, 42 | 43 | this._doCallNoAuth = function(route, method, data, callback) { 44 | console.log('Route: noauth post :'+url+route); 45 | var formData = new FormData(); 46 | for ( var key in data ) { 47 | formData.append(key, data[key]); 48 | } 49 | 50 | fetch(url+route, { 51 | method: method, 52 | headers: { 53 | 'Accept': 'application/json', 54 | 'Content-Type': 'application/json', 55 | }, 56 | //body: JSON.stringify(data) 57 | body: formData 58 | }) 59 | .then((response) => response.json()) 60 | .then((responseText) => { 61 | console.log('Called: '+route); 62 | callback(responseText); 63 | }) 64 | .catch((error) => { 65 | callback(error); 66 | }); 67 | }, 68 | 69 | this._doCallAuthGet = function(route, method, token, callback) { 70 | console.log('Route: auth get :'+url+route); 71 | return fetch(url+route, { 72 | method: method, 73 | headers: { 74 | 'Accept': 'application/json', 75 | 'Content-Type': 'application/json', 76 | 'X-Auth-Token': token 77 | }, 78 | }) 79 | .then((response) => response.json()) 80 | .then((responseText) => { 81 | callback(responseText); 82 | }) 83 | .catch((error) => { 84 | callback(error); 85 | }); 86 | }, 87 | 88 | this._doCallAuth = function(route, method, data, token, callback) { 89 | console.log('Route: auth post :'+url+route); 90 | var formData = new FormData(); 91 | for ( var key in data ) { 92 | formData.append(key, data[key]); 93 | } 94 | 95 | return fetch(url+route, { 96 | method: method, 97 | headers: { 98 | 'Accept': 'application/json', 99 | 'Content-Type': 'application/json', 100 | 'X-Auth-Token': token 101 | }, 102 | body: formData 103 | }) 104 | .then((response) => response.json()) 105 | .then((responseText) => { 106 | callback(responseText); 107 | }) 108 | .catch((error) => { 109 | callback(error); 110 | }); 111 | }, 112 | 113 | this._doCallFetchAccount = function(route, method, data, callback) { 114 | return fetch(url+route, { 115 | method: method, 116 | headers: { 117 | 'Accept': 'application/json', 118 | 'Content-Type': 'application/json', 119 | 'X-IDNumber': data.AccountHolderIdentificationNumber, 120 | 'X-GivenName': data.AccountHolderGivenName, 121 | 'X-FamilyName': data.AccountHolderFamilyName, 122 | 'X-EmailAddress': data.AccountHolderEmailAddress, 123 | }, 124 | }) 125 | .then((response) => response.json()) 126 | .then((responseText) => { 127 | callback(responseText); 128 | }) 129 | .catch((error) => { 130 | callback(error); 131 | }); 132 | }, 133 | 134 | this.authLogin = function (data, cb) { 135 | this._doCallNoAuth('/auth/login', 'POST', data, cb); 136 | }, 137 | 138 | this.authCreate = function(data, cb) { 139 | this._doCallNoAuth('/auth/account', 'POST', data, cb); 140 | }, 141 | 142 | this.fetchAccount = function(data, cb) { 143 | this._doCallFetchAccount('/accountRetrieve', 'GET', data, cb); 144 | }, 145 | 146 | this.authExtend = function(token, cb) { 147 | this._doCallAuth('/auth', 'POST', {}, token, cb); 148 | }, 149 | 150 | this.accountCreate = function(data, cb) { 151 | console.log(JSON.stringify(data)); 152 | this._doCallNoAuth('/account', 'POST', data, cb); 153 | }, 154 | 155 | this.paymentCredit = function(data, cb) { 156 | let token = this.getToken(); 157 | this._doCallAuth('/transaction/credit', 'POST', data, token, cb); 158 | }, 159 | 160 | this.paymentDeposit = function(data, cb) { 161 | let token = this.getToken(); 162 | this._doCallAuth('/transaction/deposit', 'POST', data, token, cb); 163 | }, 164 | 165 | this.accountGet = function(data, cb) { 166 | let token = this.getToken(); 167 | this._doCallAuthGet('/account', 'GET', token, cb); 168 | }, 169 | 170 | this.accountGetById = function(data, cb) { 171 | let token = this.getToken(); 172 | this._doCallAuthGet('/account/'+data.accountID, 'GET', token, cb); 173 | }, 174 | 175 | this.accountGetAll = function(data, cb) { 176 | let token = this.getToken(); 177 | this._doCallAuthGet('/account/all', 'GET', token, cb); 178 | }, 179 | 180 | this.authRemove = function(data, cb) { 181 | let token = this.getToken(); 182 | this._doCallAuth('/auth/account', 'DELETE', data, token, cb); 183 | } 184 | 185 | this.addPushToken = function(data, cb) { 186 | let token = this.getToken(); 187 | this._doCallAuth('/accountPushToken', 'POST', data, token, cb); 188 | } 189 | 190 | this.removePushToken = function(data, cb) { 191 | let token = this.getToken(); 192 | this._doCallAuth('/accountPushToken', 'DELETE', data, token, cb); 193 | } 194 | 195 | this.transactionsList = function(data, cb) { 196 | let token = this.getToken(); 197 | this._doCallAuthGet('/transaction/list/'+data.perPage+'/'+data.page, 'GET', token, cb); 198 | }, 199 | 200 | this.transactionsListAfterTimestamp = function(data, cb) { 201 | let token = this.getToken(); 202 | this._doCallAuthGet('/transaction/list/'+data.perPage+'/'+data.page+'/'+data.timestamp, 'GET', token, cb); 203 | }, 204 | 205 | this.accountSearch = function(data, cb) { 206 | let token = this.getToken(); 207 | this._doCallAuth('/account/search', 'POST', data, token, cb); 208 | }, 209 | 210 | // Token 211 | this.getToken = function() { 212 | let tokenResult = db.objects('AccountToken'); 213 | if (tokenResult.length > 0) { 214 | let tokenDB = tokenResult.slice(0,1); 215 | let tokenObj = tokenDB[0]; 216 | var token = tokenObj.Token; 217 | console.log("Get token"); 218 | console.log(token); 219 | 220 | // Check token 221 | this.authExtend(token, this.extendTokenInBackground); 222 | // Return 223 | console.log("After extend: "+token); 224 | return token; 225 | } 226 | }, 227 | 228 | this.extendTokenInBackground = function(res) { 229 | 230 | if (typeof res.error != 'undefined') { 231 | if (res.error == 'httpApiHandlers: Token invalid') { 232 | Actions.login({ type : "reset" }); 233 | console.log("Token invalid, go to login"); 234 | return; 235 | /* 236 | console.log("token invalid"); 237 | let userAuth = db.objects('AccountAuth'); 238 | if (userAuth.length > 0) { 239 | var userAccount = userAuth.slice(0,1); 240 | userAccount = userAccount[0]; 241 | 242 | console.log("User account in extend"); 243 | let data = { User: userAccount.AccountNumber, Password: userAccount.Password }; 244 | //@FIXME Missing context, cannot see "this" probably due to being passed as a callback 245 | let res = this.authLogin(data, function(res) { 246 | console.log("At second login: "); 247 | console.log(res); 248 | if (typeof res.error == 'undefined') { 249 | // Get token 250 | tokenRes = res.response; 251 | console.log("New token: "+tokenRes); 252 | db.write(() => { 253 | // Delete tokens 254 | let allTokens = db.objects('AccountToken'); 255 | db.delete(allTokens); 256 | 257 | db.create('AccountToken', { 258 | Token: tokenRes, 259 | //Timestamp: Math.floor(Date.now()) 260 | Timestamp: 1 261 | }); 262 | }); 263 | return tokenRes; 264 | } else { 265 | // Show error 266 | Alert.alert('Error', res.error); 267 | dismissKeyboard(); 268 | return; 269 | } 270 | }); 271 | } 272 | */ 273 | } 274 | } 275 | } 276 | } 277 | 278 | module.exports = BankClient; 279 | -------------------------------------------------------------------------------- /LoginView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | Image, 12 | Alert 13 | } from 'react-native'; 14 | 15 | import Button from 'react-native-button' 16 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 17 | 18 | let styles = require('./styles'); 19 | let BankClient = require('./libs/BankClient'); 20 | let bc = new BankClient(); 21 | let db = require('./libs/RealmDB'); 22 | let dismissKeyboard = require('dismissKeyboard'); 23 | 24 | let PushNotification = require('react-native-push-notification'); 25 | 26 | PushNotification.configure({ 27 | 28 | // (optional) Called when Token is generated (iOS and Android) 29 | onRegister: function(token) { 30 | let tokenString = token.token; 31 | console.log( 'TOKEN:', tokenString ); 32 | 33 | if (typeof tokenString != undefined) { 34 | // Save in database 35 | db.write(() => { 36 | // Delete tokens 37 | let allTokens = db.objects('DeviceToken'); 38 | db.delete(allTokens); 39 | 40 | db.create('DeviceToken', { 41 | Token: tokenString, 42 | Platform: "ios" 43 | }); 44 | }); 45 | } 46 | }, 47 | 48 | // (required) Called when a remote or local notification is opened or received 49 | onNotification: function(notification) { 50 | console.log( 'NOTIFICATION:', notification ); 51 | alert(notification.message); 52 | }, 53 | 54 | // ANDROID ONLY: (optional) GCM Sender ID. 55 | senderID: "YOUR GCM SENDER ID", 56 | 57 | // IOS ONLY (optional): default: all - Permissions to register. 58 | permissions: { 59 | alert: true, 60 | badge: true, 61 | sound: true 62 | }, 63 | 64 | // Should the initial notification be popped automatically 65 | // default: true 66 | popInitialNotification: true, 67 | 68 | /** 69 | * IOS ONLY: (optional) default: true 70 | * - Specified if permissions will requested or not, 71 | * - if not, you must call PushNotificationsHandler.requestPermissions() later 72 | */ 73 | requestPermissions: true, 74 | }); 75 | 76 | var LoginView = React.createClass({ 77 | getInitialState() { 78 | dismissKeyboard(); 79 | this.addPushTokenInit(); 80 | return { 81 | password: '' 82 | } 83 | }, 84 | 85 | _doLogin: function() { 86 | // Check password 87 | let userAuth = db.objects('AccountAuth'); 88 | if (userAuth.length > 0) { 89 | var userAccount = userAuth.slice(0,1); 90 | userAccount = userAccount[0]; 91 | 92 | console.log(userAccount.Password); 93 | if (userAccount.Password != this.state.password) { 94 | Alert.alert('Auth Failure', 'Password incorrect'); 95 | return; 96 | } 97 | 98 | // @TODO Maybe check and try to extend existing auth token? 99 | // For now we just delete and get a new one 100 | // Repeated logging in will fill up Redis with tokens 101 | let data = { User: userAccount.AccountNumber, Password: userAccount.Password }; 102 | let res = bc.authLogin(data, function(res) { 103 | console.log(res); 104 | if (typeof res.error == 'undefined') { 105 | // Get token 106 | let token = res.response; 107 | db.write(() => { 108 | // Delete tokens 109 | let allTokens = db.objects('AccountToken'); 110 | db.delete(allTokens); 111 | 112 | db.create('AccountToken', { 113 | Token: token, 114 | //Timestamp: Math.floor(Date.now()) 115 | Timestamp: 1 116 | }); 117 | }); 118 | // Go to account landing view 119 | dismissKeyboard(); 120 | Actions.main({type : "reset"}); 121 | //Actions.refresh({key: 'drawer', open: value => !value}); 122 | } else { 123 | // Show error 124 | Alert.alert('Error', res.error); 125 | dismissKeyboard(); 126 | return; 127 | } 128 | }); 129 | } else { 130 | dismissKeyboard(); 131 | // Check if an account exists 132 | let userAccount = db.objects('Account'); 133 | if (userAccount.length == 0) { 134 | Actions.register(); 135 | return; 136 | } 137 | // Send login 138 | let data = { User: userAccount[0].AccountNumber, Password: this.state.password }; 139 | let res = bc.authLogin(data, function(res) { 140 | console.log(res); 141 | if (typeof res.error == 'undefined') { 142 | // Get token 143 | let token = res.response; 144 | db.write(() => { 145 | // Delete tokens 146 | let allTokens = db.objects('AccountToken'); 147 | db.delete(allTokens); 148 | 149 | db.create('AccountToken', { 150 | Token: token, 151 | //Timestamp: Math.floor(Date.now()) 152 | Timestamp: 1 153 | }); 154 | }); 155 | // Go to account landing view 156 | dismissKeyboard(); 157 | Actions.main({type : "reset"}); 158 | //Actions.refresh({key: 'drawer', open: value => !value}); 159 | } else { 160 | // Show error 161 | Alert.alert('Error', res.error); 162 | dismissKeyboard(); 163 | return; 164 | } 165 | }); 166 | } 167 | }, 168 | 169 | checkAccount: function() { 170 | let userAccount = db.objects('Account'); 171 | if (userAccount.length == 0) { 172 | // There is no account set up yet 173 | // Show fetch account screen 174 | Actions.accountFetch(); 175 | } 176 | }, 177 | 178 | addPushTokenInit: function() { 179 | // Testing 180 | /* 181 | let pushToken = "test-push-token-ios-2"; 182 | let platform = "ios"; 183 | let data = { PushToken: pushToken, Platform: platform }; 184 | bc.addPushToken(data, () => { 185 | console.log("push token added"); 186 | }); 187 | */ 188 | 189 | // Fetch token 190 | // * @FIXME This is currently throwing "Error: Object type 'DeviceToken' not present in Realm" 191 | let pushTokenObj = db.objects('DeviceToken'); 192 | console.log('Push token:'); 193 | console.log(pushTokenObj); 194 | if (pushTokenObj.length > 0) { 195 | var pushTokenArr = pushTokenObj.slice(0,1); 196 | let pushToken = pushTokenArr[0]; 197 | console.log(pushToken); 198 | let pToken = pushToken.Token; 199 | let platform = pushToken.Platform; 200 | let data = { PushToken: pToken, Platform: platform }; 201 | console.log(data); 202 | bc.addPushToken(data, () => { 203 | console.log("push token added"); 204 | }); 205 | } else { 206 | console.log("No token, get the token"); 207 | PushNotification.checkPermissions(function(res) { 208 | console.log(res); 209 | }); 210 | PushNotification.abandonPermissions(); 211 | PushNotification.requestPermissions(); 212 | } 213 | }, 214 | 215 | render: function() { 216 | return ( 217 | 218 | 219 | 220 | 221 | 222 | 223 | this.setState({password})} 226 | value={this.state.password} 227 | autoCorrect={false} 228 | keyboardAppearance="dark" 229 | secureTextEntry={true} 230 | autoCapitalize="none" 231 | placeholder="Password" 232 | /> 233 | 235 | 236 | 237 | 238 | ) 239 | } 240 | }); 241 | 242 | module.exports = LoginView; 243 | -------------------------------------------------------------------------------- /android/app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /MainAccountView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react'; 4 | import { 5 | AppRegistry, 6 | Text, 7 | View, 8 | StatusBar, 9 | StyleSheet, 10 | TextInput, 11 | Image, 12 | TouchableOpacity, 13 | ListView, 14 | Alert 15 | } from 'react-native'; 16 | 17 | import Button from 'react-native-button' 18 | import {Scene, Router, TabBar, Modal, Schema, Actions, Reducer} from 'react-native-router-flux' 19 | 20 | let styles = require('./styles'); 21 | let BankClient = require('./libs/BankClient'); 22 | let bc = new BankClient(); 23 | let db = require('./libs/RealmDB'); 24 | let dismissKeyboard = require('dismissKeyboard'); 25 | 26 | let PushNotification = require('react-native-push-notification'); 27 | 28 | var MainAccountView = React.createClass({ 29 | getInitialState() { 30 | console.log('create db:', db.path) 31 | dismissKeyboard(); 32 | let transactions = db.objects('Transactions').sorted('Timestamp', 'reverse').slice(0, 5); 33 | var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); 34 | return { 35 | balance: "", 36 | balanceDecimal: "", 37 | dataSource: ds.cloneWithRows(transactions), 38 | } 39 | }, 40 | 41 | getInitialBalance: function() { 42 | let user = db.objects('Account'); 43 | var userAccount = user; 44 | //var userAccount = user.slice(0,1).first; 45 | if (userAccount.length == 0) { 46 | actions.login({ type: "reset" }); 47 | return; 48 | } 49 | userAccount = userAccount[0]; 50 | console.log(userAccount); 51 | 52 | var balance = Math.floor(userAccount.AccountBalance); 53 | let balanceDecimal = Math.round((userAccount.AccountBalance - balance) * 100); 54 | balance = this.numberWithCommas(balance); 55 | this.setState({ 'balance' : balance }); 56 | this.setState({ 'balanceDecimal' : balanceDecimal }); 57 | }, 58 | 59 | _updateAccount: function() { 60 | console.log('updating account...'); 61 | // Get latest balances 62 | let data = {}; 63 | let res = bc.accountGet(data, function(res) { 64 | if (typeof res.error == 'undefined') { 65 | console.log(res.response); 66 | let userAccountDetails = res.response; 67 | 68 | db.write(() => { 69 | // Update Main Account 70 | let userUpdate = db.objects('Account'); 71 | var userAccountUpdate = userUpdate.filtered('AccountNumber == $0', userAccountDetails.AccountNumber); 72 | console.log("User from response:"); 73 | console.log(userAccountDetails); 74 | console.log("UserAccountNumber from response:"); 75 | console.log(userAccountDetails.AccountNumber); 76 | console.log("User from DB:"); 77 | console.log(userAccountUpdate); 78 | //var userAccountUpdate = userUpdate.slice(0,1).first; 79 | if (userAccountUpdate.length == 0) { 80 | // @FIXME There are cases where the user stored in the accounts table and the user sent to log in 81 | // are two different users. Find the cause and fix. For now we throw an error and send the user out 82 | alert("Account stored in database is not the same as login!"); 83 | // Delete all other accounts for now 84 | let accounts = db.objects('Account'); 85 | db.delete(accounts); 86 | let contacts = db.objects('Contacts'); 87 | db.delete(contacts); 88 | let transactions = db.objects('Transactions'); 89 | db.delete(transactions); 90 | let auth = db.objects('AccountAuth'); 91 | db.delete(auth); 92 | let authToken = db.objects('AccountToken'); 93 | db.delete(authToken); 94 | let accountMeta = db.objects('AccountMeta'); 95 | db.delete(accountMeta); 96 | let deviceToken = db.objects('DeviceToken'); 97 | db.delete(deviceToken); 98 | Actions.login({ type: "reset" }); 99 | return; 100 | } 101 | 102 | userAccountUpdate = userAccountUpdate[0]; 103 | 104 | let accountBalance = parseFloat(userAccountDetails.AvailableBalance); 105 | let overdraft = parseFloat(userAccountDetails.Overdraft); 106 | let availableBalance = parseFloat(userAccountDetails.AccountBalance); 107 | 108 | userAccountUpdate.AccountHolderName = userAccountDetails.AccountHolderName; 109 | userAccountUpdate.Overdraft = overdraft; 110 | userAccountUpdate.AvailableBalance = availableBalance; 111 | userAccountUpdate.AccountBalance = accountBalance; 112 | 113 | }); 114 | } else { 115 | Alert.alert('Error', 'Could not update account details: '+res.error); 116 | console.log(res); 117 | dismissKeyboard(); 118 | return; 119 | } 120 | }); 121 | }, 122 | 123 | _updateTransactions: function() { 124 | console.log('updating transcations...'); 125 | // Get latest transactions 126 | let transactionsRes = db.objects('Transactions'); 127 | var transactionsResSorted = transactionsRes.sorted('Timestamp'); 128 | var timestamp = 0 129 | if (transactionsResSorted.length > 0) { 130 | // Get latest 131 | let latestTransaction = transactionsResSorted.slice(transactionsResSorted.length - 1, transactionsResSorted.length); 132 | if (latestTransaction.length > 0) { 133 | timestamp = latestTransaction[0].Timestamp; 134 | } 135 | } 136 | 137 | // We set up the data to fetch 5 records 138 | let data = { 139 | perPage : 5, 140 | page : 0, 141 | timestamp : timestamp 142 | }; 143 | console.log(data); 144 | 145 | let res = bc.transactionsListAfterTimestamp(data, function(res) { 146 | console.log("After transactions..."); 147 | if (typeof res.error == 'undefined') { 148 | let transactionList = res.response; 149 | db.write(() => { 150 | transactionList.forEach(function(t) { 151 | console.log(t); 152 | // Check if transaction exists 153 | let trDB = db.objects('Transactions').filtered('Transaction == $0', t.ID); 154 | 155 | if (trDB.length == 0) { 156 | var senderName = ""; 157 | var receiverName = ""; 158 | 159 | var contact = db.objects('Contacts').filtered('ContactAccountNumber == $0 && ContactBankNumber == $1', t.Receiver.AccountNumber, t.Receiver.BankNumber); 160 | if (contact.length > 0) { 161 | receiverName = contact[0].ContactName; 162 | } 163 | 164 | contact = db.objects('Contacts').filtered('ContactAccountNumber == $0 && ContactBankNumber == $1', t.Sender.AccountNumber, t.Sender.BankNumber); 165 | if (contact.length > 0) { 166 | senderName = contact[0].ContactName; 167 | } 168 | 169 | let transactionAmount = parseFloat(t.Amount); 170 | let feeAmount = parseFloat(t.Fee); 171 | 172 | db.create('Transactions', { 173 | Transaction: t.ID, 174 | Type: t.PainType, 175 | SenderAccountNumber: t.Sender.AccountNumber, 176 | SenderBankNumber: t.Sender.BankNumber, 177 | ReceiverAccountNumber: t.Receiver.AccountNumber, 178 | ReceiverBankNumber: t.Receiver.BankNumber, 179 | TransactionAmount: transactionAmount, 180 | SenderName: senderName, 181 | ReceiverName: receiverName, 182 | FeeAmount: feeAmount, 183 | Lat: t.Geo[0], 184 | Lon: t.Geo[1], 185 | Desc: t.Desc, 186 | Status: t.Status, 187 | Timestamp: t.Timestamp, 188 | }); 189 | } 190 | }); 191 | }); 192 | } else { 193 | Alert.alert('Error', 'Could not update account details: '+res.error); 194 | console.log(res); 195 | dismissKeyboard(); 196 | return; 197 | } 198 | }); 199 | }, 200 | 201 | updateStateListener: function() { 202 | // Fetch account 203 | let user = db.objects('Account'); 204 | var userAccount = user.slice(0,1); 205 | userAccount = userAccount[0]; 206 | var balance = Math.floor(userAccount.AccountBalance); 207 | let balanceDecimal = Math.round((userAccount.AccountBalance - balance) * 100); 208 | balance = this.numberWithCommas(balance); 209 | this.setState({ 'balance' : balance }); 210 | this.setState({ 'balanceDecimal' : balanceDecimal }); 211 | }, 212 | 213 | updateTransactionListener: function() { 214 | // Fetch transactions 215 | let transactions = db.objects('Transactions').sorted('Timestamp', 'reverse').slice(0, 5); 216 | var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); 217 | this.setState({ dataSource: ds.cloneWithRows(transactions) }); 218 | }, 219 | 220 | componentWillMount: function() { 221 | this.getInitialBalance(); 222 | // Clear notification count 223 | PushNotification.setApplicationIconBadgeNumber(0); 224 | }, 225 | 226 | componentDidMount: function() { 227 | // Update balance 228 | this._updateAccount(); 229 | // Update transaction list 230 | this._updateTransactions(); 231 | // Observe Realm Change Events 232 | db.addListener('change', this.updateStateListener); 233 | db.addListener('change', this.updateTransactionListener); 234 | }, 235 | 236 | componentWillUnmount: function() { 237 | // Remove the listener 238 | db.removeListener('change', this.updateStateListener); 239 | db.removeListener('change', this.updateTransactionListener); 240 | }, 241 | 242 | numberWithCommas: function(x) { 243 | return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 244 | }, 245 | 246 | timeConverter: function(UNIX_timestamp) { 247 | var a = new Date(UNIX_timestamp * 1000); 248 | var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; 249 | var year = a.getFullYear(); 250 | var month = months[a.getMonth()]; 251 | var date = a.getDate(); 252 | var hour = a.getHours(); 253 | var min = a.getMinutes(); 254 | var sec = a.getSeconds(); 255 | var time = date + ' ' + month + ' ' + year + ' ' + hour + ':' + min + ':' + sec ; 256 | return time; 257 | }, 258 | 259 | render: function() { 260 | var notificationMessage; 261 | if (typeof(this.props.message) != 'undefined') { 262 | notificationMessage = {this.props.message}; 263 | } 264 | 265 | return ( 266 | 267 | 268 | 269 | 270 | 271 | 272 | ACCOUNT 273 | {notificationMessage} 274 | 275 | 276 | {this.state.balance} 277 | . {this.state.balanceDecimal} 278 | 279 | 280 | 285 | 287 | Actions.transaction({ data: rowData })} style={styles.transaction.desc}>{rowData.Desc} 288 | Actions.transaction({ data: rowData })} style={styles.transaction.time}>{this.timeConverter(rowData.Timestamp)} 289 | } 290 | /> 291 | 292 | 293 | 294 | ) 295 | } 296 | }); 297 | 298 | module.exports = MainAccountView; 299 | --------------------------------------------------------------------------------