├── .gitignore ├── app ├── .babelrc ├── .buckconfig ├── .eslintrc.json ├── .flowconfig ├── .gitattributes ├── .watchmanconfig ├── __tests__ │ ├── index.android.js │ └── index.ios.js ├── android │ ├── app │ │ ├── BUCK │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets │ │ │ └── fonts │ │ │ │ ├── Entypo.ttf │ │ │ │ ├── EvilIcons.ttf │ │ │ │ ├── Feather.ttf │ │ │ │ ├── FontAwesome.ttf │ │ │ │ ├── Foundation.ttf │ │ │ │ ├── Ionicons.ttf │ │ │ │ ├── MaterialCommunityIcons.ttf │ │ │ │ ├── MaterialIcons.ttf │ │ │ │ ├── Octicons.ttf │ │ │ │ ├── SimpleLineIcons.ttf │ │ │ │ ├── Zocial.ttf │ │ │ │ └── norwester.ttf │ │ │ ├── java │ │ │ └── com │ │ │ │ └── rnnavtest │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── keystores │ │ ├── BUCK │ │ └── debug.keystore.properties │ └── settings.gradle ├── app.json ├── index.android.js ├── index.ios.js ├── ios │ ├── rnnavtest-tvOS │ │ └── Info.plist │ ├── rnnavtest-tvOSTests │ │ └── Info.plist │ ├── rnnavtest.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── rnnavtest-tvOS.xcscheme │ │ │ └── rnnavtest.xcscheme │ ├── rnnavtest │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── rnnavtestTests │ │ ├── Info.plist │ │ └── rnnavtestTests.m ├── package.json └── src │ ├── app.ios.js │ ├── assets │ └── fonts │ │ └── norwester.ttf │ ├── config.js │ ├── modules │ ├── auth │ │ ├── auth.api.js │ │ ├── auth.reducer.js │ │ └── auth.service.js │ ├── errors │ │ ├── error.reducer.js │ │ └── error.service.js │ └── utils │ │ ├── appIcons.js │ │ └── utils.service.js │ ├── store │ ├── configureStore.js │ ├── middleware.js │ └── rootReducer.js │ ├── viewcomponents │ └── ErrorBar.js │ └── viewscreens │ ├── About.js │ ├── Home.js │ ├── LoggedIn.js │ ├── Login.js │ ├── Register.js │ ├── index.js │ └── style.js ├── readme.md ├── screens.png └── server ├── .eslintrc.json ├── .gitignore ├── config ├── auth.js └── mongo.js ├── controllers ├── auth.api.js ├── auth.js └── error.js ├── index.js ├── models ├── LoginActivity.js └── Users.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | #Custom 2 | # 3 | *.env 4 | 5 | # OSX 6 | # 7 | .DS_Store 8 | 9 | # Xcode 10 | # 11 | build/ 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata 21 | *.xccheckout 22 | *.moved-aside 23 | DerivedData 24 | *.hmap 25 | *.ipa 26 | *.xcuserstate 27 | project.xcworkspace 28 | 29 | # Android/IntelliJ 30 | # 31 | build/ 32 | .idea 33 | .gradle 34 | local.properties 35 | *.iml 36 | 37 | # node.js 38 | # 39 | node_modules/ 40 | npm-debug.log 41 | yarn-error.log 42 | 43 | # BUCK 44 | buck-out/ 45 | \.buckd/ 46 | *.keystore 47 | 48 | # fastlane 49 | # 50 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 51 | # screenshots whenever they are needed. 52 | # For more information about the recommended setup visit: 53 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 54 | 55 | fastlane/report.xml 56 | fastlane/Preview.html 57 | fastlane/screenshots 58 | -------------------------------------------------------------------------------- /app/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } 4 | -------------------------------------------------------------------------------- /app/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /app/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:react/recommended", 9 | "plugin:react-native/all" 10 | ], 11 | "parserOptions": { 12 | "ecmaFeatures": { 13 | "experimentalObjectRestSpread": true, 14 | "jsx": true 15 | }, 16 | "ecmaVersion": 2017, 17 | "sourceType": "module" 18 | }, 19 | "plugins": ["react", "react-native"], 20 | "rules": { 21 | "indent": ["error", "tab"], 22 | "linebreak-style": ["error", "unix"], 23 | "quotes": ["error", "single"], 24 | "no-unused-vars": [0, { "vars": "all", "args": "after-used" }], 25 | "no-console": [0], 26 | "react/prop-types": [0], 27 | "react-native/no-color-literals": [0], 28 | "react-native/no-inline-styles": [0] 29 | }, 30 | "globals": { 31 | "require": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | .*/Libraries/react-native/ReactNative.js 16 | 17 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | emoji=true 26 | 27 | module.system=haste 28 | 29 | experimental.strict_type_args=true 30 | 31 | munge_underscores=true 32 | 33 | 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\|pdf\)$' -> 'RelativeImageStub' 34 | 35 | suppress_type=$FlowIssue 36 | suppress_type=$FlowFixMe 37 | suppress_type=$FixMe 38 | 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-5]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-5]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 41 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 42 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 43 | 44 | unsafe.enable_getters_and_setters=true 45 | 46 | [version] 47 | ^0.45.0 48 | -------------------------------------------------------------------------------- /app/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /app/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /app/__tests__/index.android.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.android.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /app/__tests__/index.ios.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.ios.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /app/android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.rnnavtest", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.rnnavtest", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /app/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: "../../node_modules/react-native/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 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 37 | * // for example: to disable dev mode in the staging build type (if configured) 38 | * devDisabledInStaging: true, 39 | * // The configuration property can be in the following formats 40 | * // 'devDisabledIn${productFlavor}${buildType}' 41 | * // 'devDisabledIn${buildType}' 42 | * 43 | * // the root of your project, i.e. where "package.json" lives 44 | * root: "../../", 45 | * 46 | * // where to put the JS bundle asset in debug mode 47 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 48 | * 49 | * // where to put the JS bundle asset in release mode 50 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 51 | * 52 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 53 | * // require('./image.png')), in debug mode 54 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 55 | * 56 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 57 | * // require('./image.png')), in release mode 58 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 59 | * 60 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 61 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 62 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 63 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 64 | * // for example, you might want to remove it from here. 65 | * inputExcludes: ["android/**", "ios/**"], 66 | * 67 | * // override which node gets called and with what additional arguments 68 | * nodeExecutableAndArgs: ["node"], 69 | * 70 | * // supply additional arguments to the packager 71 | * extraPackagerArgs: [] 72 | * ] 73 | */ 74 | 75 | apply from: "../../node_modules/react-native/react.gradle" 76 | 77 | /** 78 | * Set this to true to create two separate APKs instead of one: 79 | * - An APK that only works on ARM devices 80 | * - An APK that only works on x86 devices 81 | * The advantage is the size of the APK is reduced by about 4MB. 82 | * Upload all the APKs to the Play Store and people will download 83 | * the correct one based on the CPU architecture of their device. 84 | */ 85 | def enableSeparateBuildPerCPUArchitecture = false 86 | 87 | /** 88 | * Run Proguard to shrink the Java bytecode in release builds. 89 | */ 90 | def enableProguardInReleaseBuilds = false 91 | 92 | android { 93 | compileSdkVersion 23 94 | buildToolsVersion "23.0.1" 95 | 96 | defaultConfig { 97 | applicationId "com.rnnavtest" 98 | minSdkVersion 16 99 | targetSdkVersion 22 100 | versionCode 1 101 | versionName "1.0" 102 | ndk { 103 | abiFilters "armeabi-v7a", "x86" 104 | } 105 | } 106 | splits { 107 | abi { 108 | reset() 109 | enable enableSeparateBuildPerCPUArchitecture 110 | universalApk false // If true, also generate a universal APK 111 | include "armeabi-v7a", "x86" 112 | } 113 | } 114 | buildTypes { 115 | release { 116 | minifyEnabled enableProguardInReleaseBuilds 117 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 118 | } 119 | } 120 | // applicationVariants are e.g. debug, release 121 | applicationVariants.all { variant -> 122 | variant.outputs.each { output -> 123 | // For each separate APK per architecture, set a unique version code as described here: 124 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 125 | def versionCodes = ["armeabi-v7a":1, "x86":2] 126 | def abi = output.getFilter(OutputFile.ABI) 127 | if (abi != null) { // null for the universal-debug, universal-release variants 128 | output.versionCodeOverride = 129 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 130 | } 131 | } 132 | } 133 | } 134 | 135 | dependencies { 136 | compile project(':react-native-navigation') 137 | compile project(':react-native-linear-gradient') 138 | compile project(':react-native-config') 139 | compile project(':react-native-vector-icons') 140 | compile fileTree(dir: "libs", include: ["*.jar"]) 141 | compile "com.android.support:appcompat-v7:23.0.1" 142 | compile "com.facebook.react:react-native:+" // From node_modules 143 | } 144 | 145 | // Run this once to be able to run the application with BUCK 146 | // puts all compile dependencies into folder libs for BUCK to use 147 | task copyDownloadableDepsToLibs(type: Copy) { 148 | from configurations.compile 149 | into 'libs' 150 | } 151 | -------------------------------------------------------------------------------- /app/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 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout. 54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. 55 | -dontwarn android.text.StaticLayout 56 | 57 | # okhttp 58 | 59 | -keepattributes Signature 60 | -keepattributes *Annotation* 61 | -keep class okhttp3.** { *; } 62 | -keep interface okhttp3.** { *; } 63 | -dontwarn okhttp3.** 64 | 65 | # okio 66 | 67 | -keep class sun.misc.Unsafe { *; } 68 | -dontwarn java.nio.file.* 69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 70 | -dontwarn okio.** 71 | -------------------------------------------------------------------------------- /app/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/Entypo.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/Feather.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/Foundation.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/Ionicons.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/Octicons.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/SimpleLineIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/SimpleLineIcons.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/Zocial.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/norwester.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/assets/fonts/norwester.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/java/com/rnnavtest/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.rnnavtest; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "rnnavtest"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/android/app/src/main/java/com/rnnavtest/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.rnnavtest; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import com.reactnativenavigation.NavigationReactPackage; 7 | import com.BV.LinearGradient.LinearGradientPackage; 8 | import com.lugg.ReactNativeConfig.ReactNativeConfigPackage; 9 | import com.oblador.vectoricons.VectorIconsPackage; 10 | import com.facebook.react.ReactNativeHost; 11 | import com.facebook.react.ReactPackage; 12 | import com.facebook.react.shell.MainReactPackage; 13 | import com.facebook.soloader.SoLoader; 14 | 15 | import java.util.Arrays; 16 | import java.util.List; 17 | 18 | public class MainApplication extends Application implements ReactApplication { 19 | 20 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 21 | @Override 22 | public boolean getUseDeveloperSupport() { 23 | return BuildConfig.DEBUG; 24 | } 25 | 26 | @Override 27 | protected List getPackages() { 28 | return Arrays.asList( 29 | new MainReactPackage(), 30 | new NavigationReactPackage(), 31 | new LinearGradientPackage(), 32 | new ReactNativeConfigPackage(), 33 | new VectorIconsPackage() 34 | ); 35 | } 36 | }; 37 | 38 | @Override 39 | public ReactNativeHost getReactNativeHost() { 40 | return mReactNativeHost; 41 | } 42 | 43 | @Override 44 | public void onCreate() { 45 | super.onCreate(); 46 | SoLoader.init(this, /* native exopackage */ false); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | rnnavtest 3 | 4 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/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:2.2.3' 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 "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/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 | -------------------------------------------------------------------------------- /app/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/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.14.1-all.zip 6 | -------------------------------------------------------------------------------- /app/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 | -------------------------------------------------------------------------------- /app/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 | -------------------------------------------------------------------------------- /app/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /app/android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /app/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'rnnavtest' 2 | include ':react-native-navigation' 3 | project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/android/app') 4 | include ':react-native-linear-gradient' 5 | project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android') 6 | include ':react-native-config' 7 | project(':react-native-config').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-config/android') 8 | include ':react-native-vector-icons' 9 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') 10 | 11 | include ':app' 12 | -------------------------------------------------------------------------------- /app/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jwt-react-native-boilerplate", 3 | "displayName": "jwt-react-native-boilerplate" 4 | } 5 | -------------------------------------------------------------------------------- /app/index.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { AppRegistry, StyleSheet, Text, View } from 'react-native'; 9 | 10 | export default class rnnavtest extends Component { 11 | render() { 12 | return ( 13 | 14 | Welcome to React Native! 15 | 16 | To get started, edit index.android.js 17 | 18 | 19 | Double tap R on your keyboard to reload,{'\n'} 20 | Shake or press menu button for dev menu 21 | 22 | 23 | ); 24 | } 25 | } 26 | 27 | const styles = StyleSheet.create({ 28 | container: { 29 | flex: 1, 30 | justifyContent: 'center', 31 | alignItems: 'center', 32 | backgroundColor: '#F5FCFF' 33 | }, 34 | welcome: { 35 | fontSize: 20, 36 | textAlign: 'center', 37 | margin: 10 38 | }, 39 | instructions: { 40 | textAlign: 'center', 41 | color: '#333333', 42 | marginBottom: 5 43 | } 44 | }); 45 | 46 | AppRegistry.registerComponent('rnnavtest', () => rnnavtest); 47 | -------------------------------------------------------------------------------- /app/index.ios.js: -------------------------------------------------------------------------------- 1 | import App from './src/app'; 2 | 3 | const app = new App(); 4 | -------------------------------------------------------------------------------- /app/ios/rnnavtest-tvOS/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /app/ios/rnnavtest-tvOSTests/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 | -------------------------------------------------------------------------------- /app/ios/rnnavtest.xcodeproj/xcshareddata/xcschemes/rnnavtest-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /app/ios/rnnavtest.xcodeproj/xcshareddata/xcschemes/rnnavtest.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /app/ios/rnnavtest/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 | -------------------------------------------------------------------------------- /app/ios/rnnavtest/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 13 | #import "RCCManager.h" 14 | 15 | #import 16 | 17 | #import 18 | 19 | @implementation AppDelegate 20 | 21 | //ADDED BY JAY 22 | - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url 23 | sourceApplication:(NSString *)sourceApplication annotation:(id)annotation 24 | { 25 | return [RCTLinkingManager application:application openURL:url 26 | sourceApplication:sourceApplication annotation:annotation]; 27 | } 28 | 29 | - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity 30 | restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler 31 | { 32 | return [RCTLinkingManager application:application 33 | continueUserActivity:userActivity 34 | restorationHandler:restorationHandler]; 35 | } 36 | //END ADDED BY JAY 37 | 38 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 39 | { 40 | NSURL *jsCodeLocation; 41 | 42 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 43 | 44 | 45 | 46 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 47 | self.window.backgroundColor = [UIColor whiteColor]; 48 | [[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation launchOptions:launchOptions]; 49 | 50 | /* 51 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 52 | moduleName:@"rnnavtest" 53 | initialProperties:nil 54 | launchOptions:launchOptions]; 55 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 56 | 57 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 58 | UIViewController *rootViewController = [UIViewController new]; 59 | rootViewController.view = rootView; 60 | self.window.rootViewController = rootViewController; 61 | [self.window makeKeyAndVisible];*/ 62 | return YES; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /app/ios/rnnavtest/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/ios/rnnavtest/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /app/ios/rnnavtest/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | jwt-react-native-boilerplate 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleURLTypes 24 | 25 | 26 | CFBundleTypeRole 27 | Editor 28 | CFBundleURLName 29 | sgapp 30 | CFBundleURLSchemes 31 | 32 | sgapp 33 | 34 | 35 | 36 | CFBundleVersion 37 | 1 38 | LSRequiresIPhoneOS 39 | 40 | NSAppTransportSecurity 41 | 42 | NSExceptionDomains 43 | 44 | localhost 45 | 46 | NSExceptionAllowsInsecureHTTPLoads 47 | 48 | 49 | 50 | 51 | NSLocationWhenInUseUsageDescription 52 | 53 | UIAppFonts 54 | 55 | Entypo.ttf 56 | EvilIcons.ttf 57 | FontAwesome.ttf 58 | Foundation.ttf 59 | Ionicons.ttf 60 | MaterialCommunityIcons.ttf 61 | MaterialIcons.ttf 62 | Octicons.ttf 63 | SimpleLineIcons.ttf 64 | Zocial.ttf 65 | norwester.ttf 66 | Feather.ttf 67 | 68 | UILaunchStoryboardName 69 | LaunchScreen 70 | UIRequiredDeviceCapabilities 71 | 72 | armv7 73 | 74 | UISupportedInterfaceOrientations 75 | 76 | UIInterfaceOrientationPortrait 77 | UIInterfaceOrientationLandscapeLeft 78 | UIInterfaceOrientationLandscapeRight 79 | 80 | UIViewControllerBasedStatusBarAppearance 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /app/ios/rnnavtest/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 | -------------------------------------------------------------------------------- /app/ios/rnnavtestTests/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 | -------------------------------------------------------------------------------- /app/ios/rnnavtestTests/rnnavtestTests.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 14 | #import 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface rnnavtestTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation rnnavtestTests 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 = [[[RCTSharedApplication() 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 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jwt-react-native-boilerplate", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "test": "jest" 8 | }, 9 | "dependencies": { 10 | "jwt-decode": "2.2.0", 11 | "moment": "2.19.3", 12 | "react": "16.0.0-alpha.12", 13 | "react-native": "0.45.1", 14 | "react-native-config": "0.9.0", 15 | "react-native-elements": "1.0.0-beta5", 16 | "react-native-linear-gradient": "2.4.0", 17 | "react-native-navigation": "1.1.458", 18 | "react-native-safari-view": "2.0.0", 19 | "react-native-vector-icons": "4.6.0", 20 | "react-redux": "5.0.5", 21 | "redux": "3.7.1", 22 | "redux-form": "6.8.0", 23 | "redux-logger": "3.0.6", 24 | "redux-thunk": "2.2.0", 25 | "url-parse": "1.1.9" 26 | }, 27 | "devDependencies": { 28 | "babel-jest": "20.0.3", 29 | "babel-preset-react-native": "2.0.0", 30 | "eslint": "4.3.0", 31 | "eslint-plugin-react": "7.1.0", 32 | "jest": "20.0.4", 33 | "react-test-renderer": "16.0.0-alpha.12", 34 | "eslint-plugin-react-native": "3.0.1" 35 | }, 36 | "jest": { 37 | "preset": "react-native" 38 | }, 39 | "rnpm": { 40 | "assets": [ 41 | "./src/assets/fonts/" 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/app.ios.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { View, Platform } from 'react-native'; 3 | import { Navigation } from 'react-native-navigation'; 4 | import { Provider } from 'react-redux'; 5 | import { registerScreens } from './viewscreens'; 6 | import { iconsMap, iconsLoaded } from './modules/utils/appIcons'; 7 | 8 | import configureStore from './store/configureStore'; 9 | import { checkAuthStatus } from './modules/auth/auth.service'; 10 | 11 | import { defaultNavigator, defaultTabs } from './viewscreens/style'; 12 | 13 | export const store = configureStore(); 14 | registerScreens(store, Provider); 15 | 16 | const navigatorStyle = { 17 | navBarTranslucent: true, 18 | drawUnderNavBar: false, 19 | navBarTextColor: 'white', 20 | navBarButtonColor: 'white', 21 | statusBarTextColorScheme: 'light', 22 | drawUnderTabBar: false 23 | }; 24 | 25 | class App extends Component { 26 | constructor(props) { 27 | super(props); 28 | //check logged in status before starting app... 29 | //dispatch action so thunk can be used to update state when login is successfull 30 | //mapStateToProps not working on this page as it's the root of the app 31 | store.dispatch(checkAuthStatus()).then(loggedIn => { 32 | if (loggedIn) { 33 | App.startAppLoggedIn(); 34 | } else { 35 | App.startApp(); 36 | } 37 | }); 38 | } 39 | 40 | static startApp() { 41 | Navigation.startSingleScreenApp({ 42 | screen: { 43 | screen: 'testapp.Home', 44 | title: 'Welcome', 45 | navigatorStyle: { 46 | ...defaultNavigator, 47 | statusBarTextColorScheme: 'light' 48 | }, 49 | navigatorButtons: {} 50 | }, 51 | passProps: {}, 52 | animationType: 'slide-down' 53 | }); 54 | } 55 | 56 | static startAppLoggedIn() { 57 | Navigation.startTabBasedApp({ 58 | tabs: [ 59 | { 60 | label: 'Dashboard', 61 | screen: 'testapp.LoggedIn', 62 | title: 'Dashboard', 63 | navigatorStyle: defaultNavigator 64 | }, 65 | { 66 | label: 'About', 67 | screen: 'testapp.About', 68 | title: 'About', 69 | navigatorStyle: defaultNavigator 70 | } 71 | ], 72 | tabsStyle: defaultTabs, 73 | animationType: Platform.OS === 'ios' ? 'slide-down' : 'fade' 74 | }); 75 | } 76 | } 77 | export default App; 78 | -------------------------------------------------------------------------------- /app/src/assets/fonts/norwester.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaygould/jwt-react-native-boilerplate/2fd6377763557a9abe1385612b32a6fc61099010/app/src/assets/fonts/norwester.ttf -------------------------------------------------------------------------------- /app/src/config.js: -------------------------------------------------------------------------------- 1 | import Config from 'react-native-config'; 2 | export default { 3 | url: Config.API_URL, 4 | configHeaders: { 5 | Accept: 'application/json', 6 | 'Content-Type': 'application/json' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /app/src/modules/auth/auth.api.js: -------------------------------------------------------------------------------- 1 | import config from '../../config'; 2 | import { handleTokenErrors } from '../errors/error.service'; 3 | 4 | class AuthApi { 5 | static login(email, password) { 6 | return fetch(`${config.url}/api/auth/login`, { 7 | method: 'POST', 8 | body: JSON.stringify({ email: email, password: password }), 9 | headers: config.configHeaders 10 | }) 11 | .then(response => response.json()) 12 | .then(handleTokenErrors) 13 | .catch(error => { 14 | throw error; 15 | }); 16 | } 17 | static register(first, last, email, password) { 18 | return fetch(`${config.url}/api/auth/signup`, { 19 | method: 'POST', 20 | body: JSON.stringify({ first, last, email, password }), 21 | headers: config.configHeaders 22 | }) 23 | .then(response => response.json()) 24 | .then(handleTokenErrors) 25 | .catch(error => { 26 | throw error; 27 | }); 28 | } 29 | static refreshToken(refreshToken) { 30 | return fetch(`${config.url}/api/auth/refreshToken`, { 31 | method: 'POST', 32 | body: JSON.stringify({ refreshToken: refreshToken }), 33 | headers: config.configHeaders 34 | }) 35 | .then(response => response.json()) 36 | .then(handleTokenErrors) 37 | .catch(error => { 38 | throw error; 39 | }); 40 | } 41 | static checkAuthTest(token) { 42 | return fetch(`${config.url}/api/auth/getAll`, { 43 | method: 'POST', 44 | headers: { 45 | ...config.configHeaders, 46 | Authorization: 'Bearer ' + token 47 | } 48 | }) 49 | .then(response => response.json()) 50 | .then(handleTokenErrors) 51 | .catch(error => { 52 | throw error; 53 | }); 54 | } 55 | } 56 | export default AuthApi; 57 | -------------------------------------------------------------------------------- /app/src/modules/auth/auth.reducer.js: -------------------------------------------------------------------------------- 1 | // Actions 2 | export const setAuthPending = () => { 3 | return { 4 | type: 'SET_AUTH_PENDING' 5 | }; 6 | }; 7 | export const setLoginSuccess = (authToken, refreshToken) => { 8 | return { 9 | type: 'SET_LOGIN_SUCCESS', 10 | authToken, 11 | refreshToken 12 | }; 13 | }; 14 | export const setLoginError = loginError => { 15 | return { 16 | type: 'SET_LOGIN_ERROR', 17 | loginError 18 | }; 19 | }; 20 | export const setRegisterSuccess = () => { 21 | return { 22 | type: 'SET_REGISTER_SUCCESS' 23 | }; 24 | }; 25 | export const setRegisterError = regError => { 26 | return { 27 | type: 'SET_REGISTER_ERROR', 28 | regError 29 | }; 30 | }; 31 | export const setLogout = () => { 32 | return { 33 | type: 'SET_LOGOUT' 34 | }; 35 | }; 36 | export const saveAppToken = authToken => { 37 | return { 38 | type: 'SAVE_APP_TOKEN', 39 | authToken 40 | }; 41 | }; 42 | //Reducer 43 | let initialState = { 44 | authPending: false, 45 | loggedIn: false, 46 | registered: false, 47 | loginError: false, 48 | regError: false, 49 | authToken: null, 50 | refreshToken: null, 51 | tokenIsValid: null, 52 | pendingRefreshingToken: null 53 | }; 54 | 55 | export default function(state = initialState, action) { 56 | switch (action.type) { 57 | case 'SET_AUTH_PENDING': 58 | return { 59 | ...state, 60 | authPending: true 61 | }; 62 | case 'SET_LOGIN_SUCCESS': 63 | return { 64 | ...state, 65 | authPending: false, 66 | loggedIn: true, 67 | loginError: false, 68 | authToken: action.authToken, 69 | refreshToken: action.refreshToken 70 | }; 71 | case 'SET_LOGIN_ERROR': 72 | return { 73 | ...state, 74 | authPending: false, 75 | loggedIn: false, 76 | loginError: action.loginError 77 | }; 78 | case 'SET_REGISTER_SUCCESS': 79 | return { 80 | ...state, 81 | authPending: false, 82 | regError: false, 83 | registered: true 84 | }; 85 | case 'SET_REGISTER_ERROR': 86 | return { 87 | ...state, 88 | authPending: false, 89 | regError: action.regError 90 | }; 91 | case 'SET_LOGOUT': 92 | return { 93 | ...state, 94 | authToken: false, 95 | refreshToken: false, 96 | loggedIn: false 97 | }; 98 | case 'INVALID_TOKEN': 99 | return { 100 | ...state, 101 | tokenIsValid: false 102 | }; 103 | case 'REFRESHING_TOKEN': 104 | return { 105 | ...state, 106 | pendingRefreshingToken: true, 107 | tokenIsValid: false 108 | }; 109 | case 'TOKEN_REFRESHED': 110 | return { 111 | ...state, 112 | pendingRefreshingToken: null, 113 | tokenIsValid: true 114 | }; 115 | case 'SAVE_APP_TOKEN': 116 | return { 117 | ...state, 118 | authToken: action.authToken 119 | }; 120 | 121 | default: 122 | return state; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /app/src/modules/auth/auth.service.js: -------------------------------------------------------------------------------- 1 | import { AsyncStorage } from 'react-native'; 2 | import jwtDecode from 'jwt-decode'; 3 | import moment from 'moment'; 4 | import AuthApi from './auth.api'; 5 | import { asyncError, generalError } from '../errors/error.service'; 6 | import * as AuthReducer from './auth.reducer'; 7 | import App from '../../app'; 8 | import config from '../../config'; 9 | 10 | const _saveItem = async (item, selectedValue) => { 11 | try { 12 | await AsyncStorage.setItem(item, selectedValue); 13 | } catch (error) { 14 | throw error; 15 | } 16 | }; 17 | 18 | export const refreshToken = refreshToken => dispatch => { 19 | return AuthApi.refreshToken(refreshToken) 20 | .then(response => { 21 | if (response.success) { 22 | dispatch(AuthReducer.saveAppToken(response.authToken)); 23 | _saveItem('authToken', response.authToken) 24 | .then(resp => { 25 | console.log('Refresh finished'); 26 | }) 27 | .catch(error => { 28 | dispatch(asyncError(error)); 29 | }); 30 | } 31 | }) 32 | .catch(error => { 33 | dispatch(generalError(error)); 34 | }); 35 | }; 36 | 37 | // used on app startup 38 | export const checkAuthStatus = () => async dispatch => { 39 | try { 40 | const authToken = await AsyncStorage.getItem('authToken'); 41 | const refreshToken = await AsyncStorage.getItem('refreshToken'); 42 | if (authToken != null && refreshToken != null) { 43 | dispatch(AuthReducer.setLoginSuccess(authToken, refreshToken)); 44 | } 45 | return authToken; 46 | } catch (error) { 47 | dispatch(asyncError(error)); 48 | } 49 | }; 50 | 51 | export const logout = () => async dispatch => { 52 | dispatch(AuthReducer.setLogout()); 53 | try { 54 | await AsyncStorage.removeItem('authToken'); 55 | App.startApp(); 56 | } catch (error) { 57 | dispatch(asyncError(error)); 58 | } 59 | }; 60 | 61 | export const register = (first, last, email, password) => dispatch => { 62 | dispatch(AuthReducer.setAuthPending()); 63 | return AuthApi.register(first, last, email, password) 64 | .then(response => { 65 | console.log(response); 66 | if (response.success) { 67 | dispatch(AuthReducer.setRegisterSuccess()); 68 | } else { 69 | dispatch(AuthReducer.setRegisterError(response.message)); 70 | } 71 | }) 72 | .catch(error => { 73 | dispatch(generalError(error)); 74 | }); 75 | }; 76 | 77 | export const login = (email, password) => dispatch => { 78 | dispatch(AuthReducer.setAuthPending()); 79 | return AuthApi.login(email, password) 80 | .then(response => { 81 | if (response.success) { 82 | dispatch( 83 | AuthReducer.setLoginSuccess(response.authToken, response.refreshToken) 84 | ); 85 | _saveItem('authToken', response.authToken) 86 | .then(resp => { 87 | _saveItem('refreshToken', response.refreshToken) 88 | .then(resp => { 89 | App.startAppLoggedIn(); 90 | }) 91 | .catch(error => { 92 | dispatch(asyncError(error)); 93 | }); 94 | }) 95 | .catch(error => { 96 | dispatch(asyncError(error)); 97 | }); 98 | } else { 99 | dispatch(AuthReducer.setLoginError(response.message)); 100 | } 101 | }) 102 | .catch(error => { 103 | dispatch(generalError(error)); 104 | }); 105 | }; 106 | 107 | //test function on the login and logged in areas to show the JWT is working 108 | export const checkAuthTest = () => async dispatch => { 109 | try { 110 | const token = await AsyncStorage.getItem('authToken'); 111 | return AuthApi.checkAuthTest(token) 112 | .then(response => { 113 | if (response.success) { 114 | console.log('Success: ', response.message); 115 | } else { 116 | console.log('Error: ', response); 117 | } 118 | }) 119 | .catch(error => { 120 | dispatch(generalError(error)); 121 | }); 122 | } catch (error) { 123 | dispatch(asyncError(error)); 124 | } 125 | }; 126 | -------------------------------------------------------------------------------- /app/src/modules/errors/error.reducer.js: -------------------------------------------------------------------------------- 1 | // Actions 2 | export const connectionError = error => { 3 | return { 4 | type: 'CONNECTION_ERROR', 5 | error 6 | }; 7 | }; 8 | export const showError = error => { 9 | return { 10 | type: 'SHOW_ERROR', 11 | error 12 | }; 13 | }; 14 | export const removeError = () => { 15 | return { 16 | type: 'REMOVE_ERROR' 17 | }; 18 | }; 19 | 20 | //Reducer 21 | let initialState = { 22 | error: false, 23 | errorMessage: null 24 | }; 25 | 26 | export default function(state = initialState, action) { 27 | switch (action.type) { 28 | case 'CONNECTION_ERROR': 29 | return { 30 | ...state, 31 | error: true, 32 | errorMessage: action.error 33 | }; 34 | case 'SHOW_ERROR': 35 | return { 36 | ...state, 37 | error: true, 38 | errorMessage: action.error 39 | }; 40 | case 'REMOVE_ERROR': 41 | return { 42 | ...state, 43 | error: false, 44 | errorMessage: null 45 | }; 46 | 47 | default: 48 | return state; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/modules/errors/error.service.js: -------------------------------------------------------------------------------- 1 | import { AsyncStorage } from 'react-native'; 2 | import { asyncError } from '../errors/error.reducer'; 3 | import App from '../../app'; 4 | import config from '../../config'; 5 | 6 | import { store } from '../../app'; 7 | import { connectionError } from '../errors/error.reducer'; 8 | 9 | // token errors handled here to keep out of service files 10 | export const handleTokenErrors = response => { 11 | if (!response.success) { 12 | if (response.code && response.code === 'invalidToken') { 13 | store.dispatch({ type: 'INVALID_TOKEN' }); 14 | } else if (response.code && response.code == 'refreshExpired') { 15 | store.dispatch({ type: 'REFRESH_EXPIRED' }); 16 | store.dispatch(connectionError('Refresh token expired.')); 17 | } 18 | } 19 | return response; 20 | }; 21 | 22 | // general errors are for non-request specific problems that can occur with 23 | // many requests, such as network errors and app specific, general errors 24 | export const generalError = response => { 25 | if (response == 'TypeError: Network request failed') { 26 | return store.dispatch(connectionError('Network request failed')); 27 | // other checks for connection issues 28 | } else { 29 | // generic errors 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /app/src/modules/utils/appIcons.js: -------------------------------------------------------------------------------- 1 | const Ionicons = require('react-native-vector-icons/Ionicons'); 2 | const Evilicons = require('react-native-vector-icons/EvilIcons'); 3 | 4 | const icons = { 5 | 'ios-add': [Ionicons, 30, '#FFFFFF'], 6 | 'ios-home-outline': [Ionicons, 30, '#FFFFFF'], 7 | 'ios-navigate-outline': [Ionicons, 30, '#FFFFFF'], 8 | 'ios-log-in': [Ionicons, 30, '#FFFFFF'] 9 | // 'ios-navigate-outline': [Ionicons, 30, '#FFFFFF'], 10 | }; 11 | 12 | let iconsMap = {}; 13 | let iconsLoaded = new Promise((resolve, reject) => { 14 | new Promise.all( 15 | Object.keys(icons).map(iconName => 16 | icons[iconName][0].getImageSource( 17 | iconName, 18 | icons[iconName][1], 19 | icons[iconName][2] 20 | ) 21 | ) 22 | ).then(sources => { 23 | Object.keys(icons).forEach( 24 | (iconName, idx) => (iconsMap[iconName] = sources[idx]) 25 | ); 26 | resolve(true); 27 | }); 28 | }); 29 | 30 | export { iconsMap, iconsLoaded }; 31 | -------------------------------------------------------------------------------- /app/src/modules/utils/utils.service.js: -------------------------------------------------------------------------------- 1 | export const getUrlParams = search => { 2 | let hashes = search.slice(search.indexOf('?') + 1).split('&'); 3 | return hashes.reduce((params, hash) => { 4 | let [key, val] = hash.split('='); 5 | return Object.assign(params, { [key]: decodeURIComponent(val) }); 6 | }, {}); 7 | }; 8 | -------------------------------------------------------------------------------- /app/src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | import logger from 'redux-logger'; 4 | import rootReducer from './rootReducer'; 5 | import { jwt } from './middleware'; 6 | 7 | export default function configureStore(initialState) { 8 | return createStore(rootReducer, applyMiddleware(jwt, thunk, logger)); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/store/middleware.js: -------------------------------------------------------------------------------- 1 | import { logout, refreshToken } from '../modules/auth/auth.service'; 2 | 3 | let buffer = []; 4 | 5 | export const jwt = store => next => action => { 6 | buffer.push(action); 7 | if (action.type === 'INVALID_TOKEN') { 8 | let theStore = store.getState(); 9 | if ( 10 | theStore.auth && 11 | theStore.auth.authToken && 12 | theStore.auth.refreshToken 13 | ) { 14 | if (!theStore.auth.pendingRefreshingToken) { 15 | store.dispatch({ type: 'REFRESHING_TOKEN' }); 16 | store.dispatch(refreshToken(theStore.auth.refreshToken)).then(() => { 17 | // this will fire even if the refresh token is still valid or not. 18 | // if the refresh token is not valid (and therefore not able to retrieve 19 | // a new auth token), the REFRESH_EXPIRED action is fired from errors.api. 20 | store.dispatch({ type: 'TOKEN_REFRESHED' }); 21 | 22 | //get the action before the last INVALID_TOKEN (the one which got denied because of token expiration) 23 | let pos = buffer.map(e => e.type).indexOf('INVALID_TOKEN') - 1; 24 | 25 | // count back from the invalid token dispatch, and fire off the last dispatch again which was 26 | // a function. These are to be dispatched, and have the dispatch function passed through to them. 27 | for (var i = pos; i > -1; i -= 1) { 28 | if (typeof buffer[i] === 'function') { 29 | store.dispatch({ 30 | type: 'RESEND', 31 | action: buffer[i](store.dispatch) 32 | }); 33 | break; 34 | } 35 | } 36 | buffer = []; 37 | }); 38 | } 39 | } 40 | } else if (action.type === 'REFRESH_EXPIRED') { 41 | buffer = []; 42 | store.dispatch(logout()); 43 | } else { 44 | if (buffer.length > 20) { 45 | //remove all items but keep the last 20 which forms the buffer 46 | buffer.splice(0, buffer.length - 20); 47 | } 48 | return next(action); 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /app/src/store/rootReducer.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { reducer as formReducer } from 'redux-form'; 3 | import auth from '../modules/auth/auth.reducer'; 4 | import error from '../modules/errors/error.reducer'; 5 | 6 | const rootReducer = combineReducers({ 7 | auth, 8 | error, 9 | form: formReducer 10 | }); 11 | 12 | export default rootReducer; 13 | -------------------------------------------------------------------------------- /app/src/viewcomponents/ErrorBar.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { StyleSheet, Text, View } from 'react-native'; 3 | import { connect } from 'react-redux'; 4 | import { Button } from 'react-native-elements'; 5 | 6 | class ErrorBar extends Component { 7 | constructor(props) { 8 | super(props); 9 | } 10 | render() { 11 | let errorView = ( 12 | 13 | 14 | {this.props.error || null} 15 | 16 | 17 | ); 18 | return this.props.error != null ? errorView : null; 19 | } 20 | } 21 | 22 | function mapStateToProps(store) { 23 | return { 24 | error: store.error.errorMessage 25 | }; 26 | } 27 | function mapDispatchToProps(dispatch) { 28 | return {}; 29 | } 30 | 31 | export default connect(mapStateToProps, mapDispatchToProps)(ErrorBar); 32 | 33 | const styles = StyleSheet.create({ 34 | container: { 35 | alignItems: 'center', 36 | position: 'absolute', 37 | top: 0, 38 | left: 0, 39 | right: 0, 40 | backgroundColor: 'rgba(52,52,52,0.3)', 41 | padding: 10 42 | } 43 | }); 44 | -------------------------------------------------------------------------------- /app/src/viewscreens/About.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { StyleSheet, Text, View } from 'react-native'; 3 | import { connect } from 'react-redux'; 4 | import { Button } from 'react-native-elements'; 5 | import LinearGradient from 'react-native-linear-gradient'; 6 | 7 | import { logout, checkAuthTest } from '../modules/auth/auth.service'; 8 | 9 | import ErrorBar from '../viewcomponents/ErrorBar'; 10 | 11 | import { globalStyle } from './style'; 12 | 13 | class About extends Component { 14 | constructor(props) { 15 | super(props); 16 | } 17 | render() { 18 | return ( 19 | 23 | 24 | 25 | 26 | This app runs on React Native, with Redux handling local state 27 | across the application for authentication. The authentication is 28 | based around JSON Web Tokens (JWT's) which are created on a server. 29 | 30 | 31 | The server runs on Node JS with a MongoDB/Mongoose database. The app 32 | can register people to this database, and allow them to log in using 33 | their credentials. 34 | 35 | 36 | The JWT's keep the user logged in for a number of seconds until the 37 | auth token expires. If the auth token has expired, the app will save 38 | the failed request in a local buffer, and ask the server for a new 39 | auth token by sending a refresh token for authorization. If the 40 | refresh token is valid, the new auth token is sent back, and the 41 | initial buffered request is fired again. 42 | 43 | 44 | 45 | ); 46 | } 47 | } 48 | 49 | function mapStateToProps(store) { 50 | return {}; 51 | } 52 | function mapDispatchToProps(dispatch) { 53 | return {}; 54 | } 55 | 56 | export default connect(mapStateToProps, mapDispatchToProps)(About); 57 | 58 | const styles = StyleSheet.create({ 59 | container: { 60 | flex: 1, 61 | flexDirection: 'column', 62 | justifyContent: 'center', 63 | alignItems: 'center' 64 | }, 65 | textWrap: { 66 | padding: 20 67 | }, 68 | text: { 69 | backgroundColor: 'rgba(0,0,0,0)', 70 | color: '#fff', 71 | marginTop: 10 72 | } 73 | }); 74 | -------------------------------------------------------------------------------- /app/src/viewscreens/Home.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Text, View, StyleSheet, Image, StatusBar } from 'react-native'; 3 | import { connect } from 'react-redux'; 4 | import LinearGradient from 'react-native-linear-gradient'; 5 | import { Button } from 'react-native-elements'; 6 | 7 | import { globalStyle, defaultNavigator } from './style'; 8 | 9 | class Home extends Component { 10 | constructor(props) { 11 | super(props); 12 | this.goToLoginPage = this.goToLoginPage.bind(this); 13 | } 14 | 15 | goToLoginPage() { 16 | this.props.navigator.push({ 17 | screen: 'testapp.Login', 18 | title: 'Login', 19 | passProps: {}, 20 | animated: true, 21 | backButtonHidden: false, 22 | navigatorStyle: defaultNavigator, 23 | navigatorButtons: {} 24 | }); 25 | } 26 | 27 | render() { 28 | return ( 29 | 33 | 34 | 35 | JWT authentication boilerplate with Redux 36 | 37 |