Archived
Merge branch 'feature/stripe' into 'master'
Pay with stripe in app See merge request edb/dusken-client!2
This commit is contained in:
commit
65fc376e81
59 files changed
+2832
-1997
No files matched your search
+3
-3
@@ -37,12 +37,12 @@ suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
suppress_type=$FixMe
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
[version]
|
||||
^0.53.0
|
||||
^0.56.0
|
||||
+4
-1
@@ -50,10 +50,13 @@ buck-out/
|
||||
*/fastlane/report.xml
|
||||
*/fastlane/Preview.html
|
||||
*/fastlane/screenshots
|
||||
*/fastlane/test_output
|
||||
android/google_play.json
|
||||
|
||||
.env
|
||||
.env*
|
||||
*.swp
|
||||
|
||||
# Sentry
|
||||
android/sentry.properties
|
||||
ios/sentry.properties
|
||||
ios/Pods
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
image: node:latest
|
||||
image: node:carbon
|
||||
|
||||
cache:
|
||||
paths:
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
## Install
|
||||
# See https://facebook.github.io/react-native/docs/getting-started.html#content
|
||||
yarn
|
||||
cd ios; pod install # ios only
|
||||
|
||||
# Environment settings
|
||||
cp env-example .env
|
||||
|
||||
# Sentry
|
||||
# Get auth token from https://sentry.neuf.no/api/ with project:write scope
|
||||
cp ios/sentry.properties-example ios/sentry.properties
|
||||
cp android/sentry.properties-example android/sentry.properties
|
||||
|
||||
react-native start
|
||||
react-native run-android
|
||||
|
||||
@@ -22,6 +18,13 @@
|
||||
|
||||
# Make sure you have hw.keyboard=yes in your avd config.ini (in $HOME/.android/avd/.../) for reloading when pressing R twice to work.
|
||||
|
||||
## Prepare release build
|
||||
|
||||
# Sentry
|
||||
# Get auth token from https://sentry.neuf.no/api/ with project:write scope
|
||||
cp ios/sentry.properties-example ios/sentry.properties
|
||||
cp android/sentry.properties-example android/sentry.properties
|
||||
|
||||
## Create release build (Android)
|
||||
# Aquire the keystore and put it in android/app/dusken-client.keystore
|
||||
|
||||
@@ -32,10 +35,13 @@
|
||||
DUSKEN_RELEASE_KEY_PASSWORD=
|
||||
|
||||
# Build
|
||||
yarn build-android
|
||||
yarn build-android # Output is in android/app/build/outputs/apk
|
||||
|
||||
# Output is in android/app/build/outputs/apk
|
||||
# Note: Make sure you have the file android/google_play.json
|
||||
# Ref: https://docs.fastlane.tools/actions/supply/#setup
|
||||
|
||||
# Publish android build to the Google Play beta track
|
||||
yarn release-android
|
||||
|
||||
## Libraries
|
||||
|
||||
|
||||
+1
-1
@@ -1,10 +1,10 @@
|
||||
import 'react-native';
|
||||
import React from 'react';
|
||||
import App from '../src/App';
|
||||
import 'isomorphic-fetch';
|
||||
|
||||
// Note: test renderer must be required after react-native.
|
||||
import renderer from 'react-test-renderer';
|
||||
import 'isomorphic-fetch';
|
||||
|
||||
it('renders correctly', () => {
|
||||
const tree = renderer.create(
|
||||
|
||||
@@ -103,8 +103,8 @@ android {
|
||||
applicationId "no.neuf.chateau"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 23
|
||||
versionCode 17
|
||||
versionName "1.1.3"
|
||||
versionCode 19
|
||||
versionName "1.2.0"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
@@ -159,6 +159,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':tipsi-stripe')
|
||||
compile project(':react-native-sentry')
|
||||
compile project(':react-native-config')
|
||||
compile fileTree(dir: "libs", include: ["*.jar"])
|
||||
|
||||
@@ -3,6 +3,7 @@ package no.neuf.chateau;
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.gettipsi.stripe.StripeReactPackage;
|
||||
import io.sentry.RNSentryPackage;
|
||||
import com.lugg.ReactNativeConfig.ReactNativeConfigPackage;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
@@ -26,6 +27,7 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
new StripeReactPackage(),
|
||||
new RNSentryPackage(MainApplication.this),
|
||||
new ReactNativeConfigPackage()
|
||||
);
|
||||
|
||||
@@ -13,7 +13,9 @@ buildscript {
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
repositories {
|
||||
// Add jitpack repository (added by tipsi-stripe)
|
||||
maven { url "https://jitpack.io" }
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
json_key_file "google_play.json" # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
|
||||
package_name "no.neuf.chateau" # e.g. com.krausefx.app
|
||||
@@ -0,0 +1,27 @@
|
||||
# Customise this file, documentation can be found here:
|
||||
# https://docs.fastlane.tools/actions/
|
||||
# All available actions: https://docs.fastlane.tools/actions
|
||||
# can also be listed using the `fastlane actions` command
|
||||
|
||||
# Change the syntax highlighting to Ruby
|
||||
# All lines starting with a # are ignored when running `fastlane`
|
||||
|
||||
# If you want to automatically update fastlane if a new version is available:
|
||||
# update_fastlane
|
||||
|
||||
# This is the minimum version number required.
|
||||
# Update this, if you use features of a newer version
|
||||
fastlane_version "2.62.1"
|
||||
|
||||
default_platform :android
|
||||
|
||||
platform :android do
|
||||
desc "Submit a new build to the Google Play Beta track"
|
||||
lane :beta do
|
||||
# build the release variant
|
||||
gradle(task: "assembleRelease")
|
||||
|
||||
# upload to Google Play
|
||||
supply(track: "beta")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
fastlane documentation
|
||||
================
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
## Choose your installation method:
|
||||
|
||||
<table width="100%" >
|
||||
<tr>
|
||||
<th width="33%"><a href="http://brew.sh">Homebrew</a></th>
|
||||
<th width="33%">Installer Script</th>
|
||||
<th width="33%">RubyGems</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="33%" align="center">macOS</td>
|
||||
<td width="33%" align="center">macOS</td>
|
||||
<td width="33%" align="center">macOS or Linux with Ruby 2.0.0 or above</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="33%"><code>brew cask install fastlane</code></td>
|
||||
<td width="33%"><a href="https://download.fastlane.tools">Download the zip file</a>. Then double click on the <code>install</code> script (or run it in a terminal window).</td>
|
||||
<td width="33%"><code>sudo gem install fastlane -NV</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
# Available Actions
|
||||
## Android
|
||||
### android beta
|
||||
```
|
||||
fastlane android beta
|
||||
```
|
||||
Submit a new build to the Google Play Beta track
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
|
||||
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
|
||||
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
@@ -0,0 +1,4 @@
|
||||
You can do the following:
|
||||
- See your proof of membership
|
||||
- Buy or renew your membership
|
||||
- See the event schedule with all of our events
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1 @@
|
||||
Your proof of membership and the event schedule at Chateau Neuf
|
||||
@@ -0,0 +1 @@
|
||||
Chateau Neuf
|
||||
Whitespace-only changes.
@@ -0,0 +1,4 @@
|
||||
Du kan gjøre følgende
|
||||
- Se ditt medlemskapsbevis
|
||||
- Kjøpe og fornye medlemskap
|
||||
- Se programmet med alle våre arrangementer
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1 @@
|
||||
Medlemskapsbevis og program for Chateau Neuf
|
||||
@@ -0,0 +1 @@
|
||||
Chateau Neuf - Det Norske Studentersamfund
|
||||
Whitespace-only changes.
@@ -1,4 +1,6 @@
|
||||
rootProject.name = 'Dusken'
|
||||
include ':tipsi-stripe'
|
||||
project(':tipsi-stripe').projectDir = new File(rootProject.projectDir, '../node_modules/tipsi-stripe/android')
|
||||
include ':react-native-sentry'
|
||||
project(':react-native-sentry').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sentry/android')
|
||||
include ':react-native-config'
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
EVENT_API_URL=https://studentersamfundet.no
|
||||
DUSKEN_API_URL=https://galtinn.neuf.no
|
||||
DUSKEN_PURCHASE_URL=https://galtinn.neuf.no/?utm_source=purchase-button&utm_medium=app
|
||||
DUSKEN_FORGOT_PASSWORD_URL=https://galtinn.neuf.no/auth/password_reset/
|
||||
SENTRY_DSN=
|
||||
SENTRY_DSN=
|
||||
STRIPE_PUBLISHABLE_KEY=
|
||||
@@ -3,6 +3,8 @@ import { AppRegistry } from "react-native";
|
||||
import { Sentry } from 'react-native-sentry';
|
||||
import Config from 'react-native-config';
|
||||
|
||||
Sentry.config(Config.SENTRY_DSN).install();
|
||||
if(Config.SENTRY_DSN) {
|
||||
Sentry.config(Config.SENTRY_DSN).install();
|
||||
}
|
||||
|
||||
AppRegistry.registerComponent('Dusken', () => App);
|
||||
@@ -39,6 +39,7 @@
|
||||
3E46ED82B1574BB598025413 /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0A6DA7DAB38A43E2BF0FC37C /* EvilIcons.ttf */; };
|
||||
4306CBFD81DE4035B0AB4D30 /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C02D46B0229941F69264474C /* SimpleLineIcons.ttf */; };
|
||||
48652E97B0B04C15B3FA6FC3 /* MaterialIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D7A0431FBA3840039633FC3C /* MaterialIcons.ttf */; };
|
||||
4AF5FEEA965E4967AA857546 /* libTPSStripe.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 95CBCD539DBA4AE7B3D73CD0 /* libTPSStripe.a */; };
|
||||
551E4CC640DB4E68A88730B5 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 4A651C47D6FC4ED2BAB4F197 /* Zocial.ttf */; };
|
||||
5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
|
||||
65850D7E09F243FDB4F2B168 /* libRNSentry.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E3DF2205F5D4B34BF1CCCCF /* libRNSentry.a */; };
|
||||
@@ -53,6 +54,7 @@
|
||||
C867C6D3ECB7499FA2F051D6 /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E926661F17B94D69B50A0BA5 /* FontAwesome.ttf */; };
|
||||
CC801D520E86402F9AF28660 /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 390970DBF0FD44B0B4C8E2F0 /* Foundation.ttf */; };
|
||||
D218B6D7605D4C17B6540D0B /* libReactNativeConfig.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 07B9F82FBB154C258C70E333 /* libReactNativeConfig.a */; };
|
||||
F27CE4F4AEFA492262BF93F8 /* libPods-Dusken.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 584192D9AB197F8F652E4481 /* libPods-Dusken.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -245,6 +247,13 @@
|
||||
remoteGlobalIDString = 58B5119B1A9E6C1200147676;
|
||||
remoteInfo = RCTText;
|
||||
};
|
||||
871D05431F7303CD0009775B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 32A55FD2F8DE47F3BC5443BB /* TPSStripe.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 3A3A7F1A1DC27B520030F9DC;
|
||||
remoteInfo = TPSStripe;
|
||||
};
|
||||
87371BF41F6F25C200915105 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
|
||||
@@ -266,6 +275,34 @@
|
||||
remoteGlobalIDString = EB2648DF1C7BE17A00B8F155;
|
||||
remoteInfo = ReactNativeConfig;
|
||||
};
|
||||
87A2D0E41FC246C00090CBCD /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 3DBE0D001F3B181A0099AA32;
|
||||
remoteInfo = fishhook;
|
||||
};
|
||||
87A2D0E61FC246C00090CBCD /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32;
|
||||
remoteInfo = "fishhook-tvOS";
|
||||
};
|
||||
87A2D0F61FC246C00090CBCD /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 9936F3131F5F2E4B0010BF04;
|
||||
remoteInfo = privatedata;
|
||||
};
|
||||
87A2D0F81FC246C00090CBCD /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04;
|
||||
remoteInfo = "privatedata-tvOS";
|
||||
};
|
||||
87E5B2BB1F225BD50051F809 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||
@@ -313,6 +350,7 @@
|
||||
00E356EE1AD99517003FC87E /* DuskenTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DuskenTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
00E356F21AD99517003FC87E /* DuskenTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DuskenTests.m; sourceTree = "<group>"; };
|
||||
020374EEEA8B01E859226AEC /* Pods-Dusken.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Dusken.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Dusken/Pods-Dusken.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
07B9F82FBB154C258C70E333 /* libReactNativeConfig.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libReactNativeConfig.a; sourceTree = "<group>"; };
|
||||
0A6DA7DAB38A43E2BF0FC37C /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/native-base/Fonts/EvilIcons.ttf"; sourceTree = "<group>"; };
|
||||
0D8F73C46ADC4ABEBE691283 /* ReactNativeConfig.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeConfig.xcodeproj; path = "../node_modules/react-native-config/ios/ReactNativeConfig.xcodeproj"; sourceTree = "<group>"; };
|
||||
@@ -329,9 +367,11 @@
|
||||
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
|
||||
2D02E47B1E0B4A5D006451C7 /* Dusken-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Dusken-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2D02E4901E0B4A5D006451C7 /* Dusken-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Dusken-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
32A55FD2F8DE47F3BC5443BB /* TPSStripe.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = TPSStripe.xcodeproj; path = "../node_modules/tipsi-stripe/ios/TPSStripe.xcodeproj"; sourceTree = "<group>"; };
|
||||
390970DBF0FD44B0B4C8E2F0 /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/native-base/Fonts/Foundation.ttf"; sourceTree = "<group>"; };
|
||||
4A651C47D6FC4ED2BAB4F197 /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/native-base/Fonts/Zocial.ttf"; sourceTree = "<group>"; };
|
||||
4E3DF2205F5D4B34BF1CCCCF /* libRNSentry.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSentry.a; sourceTree = "<group>"; };
|
||||
584192D9AB197F8F652E4481 /* libPods-Dusken.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Dusken.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
59C3A3AC725E4DF083440735 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/native-base/Fonts/Ionicons.ttf"; sourceTree = "<group>"; };
|
||||
5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
|
||||
76F0B251D6DD45228CBC367B /* RNSentry.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNSentry.xcodeproj; path = "../node_modules/react-native-sentry/ios/RNSentry.xcodeproj"; sourceTree = "<group>"; };
|
||||
@@ -341,12 +381,15 @@
|
||||
87E5B29C1F225BD50051F809 /* dnslogo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dnslogo.png; path = Dusken/dnslogo.png; sourceTree = "<group>"; };
|
||||
8CAEF677B8A643969E0294B7 /* Roboto_medium.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Roboto_medium.ttf; path = "../node_modules/native-base/Fonts/Roboto_medium.ttf"; sourceTree = "<group>"; };
|
||||
923192359DEC49D085C78135 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
94E51283EFA6F590919438A3 /* libPods-DuskenTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-DuskenTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
95CBCD539DBA4AE7B3D73CD0 /* libTPSStripe.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libTPSStripe.a; sourceTree = "<group>"; };
|
||||
ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = "<group>"; };
|
||||
C02D46B0229941F69264474C /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = SimpleLineIcons.ttf; path = "../node_modules/native-base/Fonts/SimpleLineIcons.ttf"; sourceTree = "<group>"; };
|
||||
C559033577D34FACA86020C1 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/native-base/Fonts/Octicons.ttf"; sourceTree = "<group>"; };
|
||||
D4F0955EA08E41F69EEE0DED /* Roboto.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Roboto.ttf; path = "../node_modules/native-base/Fonts/Roboto.ttf"; sourceTree = "<group>"; };
|
||||
D7A0431FBA3840039633FC3C /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/native-base/Fonts/MaterialIcons.ttf"; sourceTree = "<group>"; };
|
||||
E926661F17B94D69B50A0BA5 /* FontAwesome.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome.ttf; path = "../node_modules/native-base/Fonts/FontAwesome.ttf"; sourceTree = "<group>"; };
|
||||
ED3E665425D2BF39C276B9FC /* Pods-Dusken.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Dusken.release.xcconfig"; path = "Pods/Target Support Files/Pods-Dusken/Pods-Dusken.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -378,6 +421,8 @@
|
||||
D218B6D7605D4C17B6540D0B /* libReactNativeConfig.a in Frameworks */,
|
||||
65850D7E09F243FDB4F2B168 /* libRNSentry.a in Frameworks */,
|
||||
83EBB8CA4CF842BA8C090802 /* libz.tbd in Frameworks */,
|
||||
4AF5FEEA965E4967AA857546 /* libTPSStripe.a in Frameworks */,
|
||||
F27CE4F4AEFA492262BF93F8 /* libPods-Dusken.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -465,6 +510,15 @@
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
06140F8A90550C16A8941EFD /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
020374EEEA8B01E859226AEC /* Pods-Dusken.debug.xcconfig */,
|
||||
ED3E665425D2BF39C276B9FC /* Pods-Dusken.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
139105B71AF99BAD00B5F7CC /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -479,6 +533,8 @@
|
||||
children = (
|
||||
139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
|
||||
3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */,
|
||||
87A2D0E51FC246C00090CBCD /* libfishhook.a */,
|
||||
87A2D0E71FC246C00090CBCD /* libfishhook-tvOS.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -513,10 +569,21 @@
|
||||
87E5B2BE1F225BD50051F809 /* libthird-party.a */,
|
||||
87E5B2C01F225BD50051F809 /* libdouble-conversion.a */,
|
||||
87E5B2C21F225BD50051F809 /* libdouble-conversion.a */,
|
||||
87A2D0F71FC246C00090CBCD /* libprivatedata.a */,
|
||||
87A2D0F91FC246C00090CBCD /* libprivatedata-tvOS.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3B33B1721C77D1DC86BC30C3 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
584192D9AB197F8F652E4481 /* libPods-Dusken.a */,
|
||||
94E51283EFA6F590919438A3 /* libPods-DuskenTests.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5E91572E1DD0AC6500FF2AA8 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -552,6 +619,7 @@
|
||||
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
|
||||
0D8F73C46ADC4ABEBE691283 /* ReactNativeConfig.xcodeproj */,
|
||||
76F0B251D6DD45228CBC367B /* RNSentry.xcodeproj */,
|
||||
32A55FD2F8DE47F3BC5443BB /* TPSStripe.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -574,6 +642,8 @@
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
95AA103233A74A28A47B99B8 /* Resources */,
|
||||
87995FD11F72F740005EB91D /* Recovered References */,
|
||||
06140F8A90550C16A8941EFD /* Pods */,
|
||||
3B33B1721C77D1DC86BC30C3 /* Frameworks */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
@@ -591,12 +661,21 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
871D05401F7303CD0009775B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
871D05441F7303CD0009775B /* libTPSStripe.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
87995FD11F72F740005EB91D /* Recovered References */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
07B9F82FBB154C258C70E333 /* libReactNativeConfig.a */,
|
||||
4E3DF2205F5D4B34BF1CCCCF /* libRNSentry.a */,
|
||||
923192359DEC49D085C78135 /* libz.tbd */,
|
||||
95CBCD539DBA4AE7B3D73CD0 /* libTPSStripe.a */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
@@ -670,11 +749,14 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Dusken" */;
|
||||
buildPhases = (
|
||||
D97D7C388D1F900D9E524C3A /* [CP] Check Pods Manifest.lock */,
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
98D2BF556B534A3FBEC71C2F /* Upload Debug Symbols to Sentry */,
|
||||
D038498A5851F0B62027363D /* [CP] Embed Pods Frameworks */,
|
||||
D9A71B546BFA13DD10E69B91 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -816,6 +898,10 @@
|
||||
ProductGroup = 87995FF41F72F741005EB91D /* Products */;
|
||||
ProjectRef = 76F0B251D6DD45228CBC367B /* RNSentry.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 871D05401F7303CD0009775B /* Products */;
|
||||
ProjectRef = 32A55FD2F8DE47F3BC5443BB /* TPSStripe.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
@@ -1003,6 +1089,13 @@
|
||||
remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
871D05441F7303CD0009775B /* libTPSStripe.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libTPSStripe.a;
|
||||
remoteRef = 871D05431F7303CD0009775B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
87371BF51F6F25C200915105 /* libRCTBlob-tvOS.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
@@ -1024,6 +1117,34 @@
|
||||
remoteRef = 879C48E21F3A5BB9007436D3 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
87A2D0E51FC246C00090CBCD /* libfishhook.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libfishhook.a;
|
||||
remoteRef = 87A2D0E41FC246C00090CBCD /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
87A2D0E71FC246C00090CBCD /* libfishhook-tvOS.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = "libfishhook-tvOS.a";
|
||||
remoteRef = 87A2D0E61FC246C00090CBCD /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
87A2D0F71FC246C00090CBCD /* libprivatedata.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libprivatedata.a;
|
||||
remoteRef = 87A2D0F61FC246C00090CBCD /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
87A2D0F91FC246C00090CBCD /* libprivatedata-tvOS.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = "libprivatedata-tvOS.a";
|
||||
remoteRef = 87A2D0F81FC246C00090CBCD /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
87E5B2BC1F225BD50051F809 /* libthird-party.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
@@ -1151,6 +1272,57 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export SENTRY_PROPERTIES=sentry.properties\n../node_modules/sentry-cli-binary/bin/sentry-cli upload-dsym";
|
||||
};
|
||||
D038498A5851F0B62027363D /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Dusken/Pods-Dusken-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D97D7C388D1F900D9E524C3A /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Dusken-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D9A71B546BFA13DD10E69B91 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-Dusken/Pods-Dusken-resources.sh",
|
||||
$PODS_CONFIGURATION_BUILD_DIR/Stripe/Stripe.bundle,
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Dusken/Pods-Dusken-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -1228,6 +1400,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-config/ios/ReactNativeConfig",
|
||||
"$(SRCROOT)/../node_modules/react-native-sentry/ios/**",
|
||||
"$(SRCROOT)/../node_modules/tipsi-stripe/ios/TPSStripe",
|
||||
);
|
||||
INFOPLIST_FILE = DuskenTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1236,6 +1409,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1255,6 +1429,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-config/ios/ReactNativeConfig",
|
||||
"$(SRCROOT)/../node_modules/react-native-sentry/ios/**",
|
||||
"$(SRCROOT)/../node_modules/tipsi-stripe/ios/TPSStripe",
|
||||
);
|
||||
INFOPLIST_FILE = DuskenTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1263,6 +1438,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1275,6 +1451,7 @@
|
||||
};
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 020374EEEA8B01E859226AEC /* Pods-Dusken.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@@ -1284,6 +1461,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-config/ios/ReactNativeConfig",
|
||||
"$(SRCROOT)/../node_modules/react-native-sentry/ios/**",
|
||||
"$(SRCROOT)/../node_modules/tipsi-stripe/ios/TPSStripe",
|
||||
);
|
||||
INFOPLIST_FILE = Dusken/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1300,6 +1478,7 @@
|
||||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = ED3E665425D2BF39C276B9FC /* Pods-Dusken.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@@ -1308,6 +1487,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-config/ios/ReactNativeConfig",
|
||||
"$(SRCROOT)/../node_modules/react-native-sentry/ios/**",
|
||||
"$(SRCROOT)/../node_modules/tipsi-stripe/ios/TPSStripe",
|
||||
);
|
||||
INFOPLIST_FILE = Dusken/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1338,6 +1518,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-config/ios/ReactNativeConfig",
|
||||
"$(SRCROOT)/../node_modules/react-native-sentry/ios/**",
|
||||
"$(SRCROOT)/../node_modules/tipsi-stripe/ios/TPSStripe",
|
||||
);
|
||||
INFOPLIST_FILE = "Dusken-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1345,6 +1526,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1374,6 +1556,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-config/ios/ReactNativeConfig",
|
||||
"$(SRCROOT)/../node_modules/react-native-sentry/ios/**",
|
||||
"$(SRCROOT)/../node_modules/tipsi-stripe/ios/TPSStripe",
|
||||
);
|
||||
INFOPLIST_FILE = "Dusken-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1381,6 +1564,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1411,6 +1595,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Dusken-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1437,6 +1622,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Dusken-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Dusken.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,176 +1,158 @@
|
||||
{
|
||||
"images":[
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"20x20",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-20x20@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"20x20",
|
||||
"scale":"3x",
|
||||
"filename":"Icon-App-20x20@3x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"29x29",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-29x29@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"29x29",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-29x29@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"29x29",
|
||||
"scale":"3x",
|
||||
"filename":"Icon-App-29x29@3x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"40x40",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-40x40@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"40x40",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-40x40@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"40x40",
|
||||
"scale":"3x",
|
||||
"filename":"Icon-App-40x40@3x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"57x57",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-57x57@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"57x57",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-57x57@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"60x60",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-60x60@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"60x60",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-60x60@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"60x60",
|
||||
"scale":"3x",
|
||||
"filename":"Icon-App-60x60@3x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"iphone",
|
||||
"size":"76x76",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-76x76@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"20x20",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-20x20@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"20x20",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-20x20@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"29x29",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-29x29@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"29x29",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-29x29@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"40x40",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-40x40@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"40x40",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-40x40@2x.png"
|
||||
},
|
||||
{
|
||||
"size" : "50x50",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Small-50x50@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "50x50",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Small-50x50@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"72x72",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-72x72@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"72x72",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-72x72@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"76x76",
|
||||
"scale":"1x",
|
||||
"filename":"Icon-App-76x76@1x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"76x76",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-76x76@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"76x76",
|
||||
"scale":"3x",
|
||||
"filename":"Icon-App-76x76@3x.png"
|
||||
},
|
||||
{
|
||||
"idiom":"ipad",
|
||||
"size":"83.5x83.5",
|
||||
"scale":"2x",
|
||||
"filename":"Icon-App-83.5x83.5@2x.png"
|
||||
}
|
||||
],
|
||||
"info":{
|
||||
"version":1,
|
||||
"author":"makeappicon"
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "57x57",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-57x57@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "57x57",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-57x57@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "50x50",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Small-50x50@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "50x50",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Small-50x50@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "72x72",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-72x72@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "72x72",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-72x72@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "app_icon.jpg",
|
||||
"scale" : "1x"
|
||||
}
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.1</string>
|
||||
<string>1.2.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>6</string>
|
||||
<string>8</string>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>comgooglemaps</string>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
platform :ios, '9.0'
|
||||
|
||||
target 'Dusken' do
|
||||
pod 'Stripe', '~> 11.2.0'
|
||||
end
|
||||
@@ -0,0 +1,12 @@
|
||||
PODS:
|
||||
- Stripe (11.2.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Stripe (~> 11.2.0)
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Stripe: 898f83a95d72180c6eb4acd65b2ae6158fc6a8bd
|
||||
|
||||
PODFILE CHECKSUM: 273d0fa628aa24ffc6ca337ff5541ea938e9910c
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
+2
-201
@@ -1,202 +1,3 @@
|
||||
/* Workaround ref: https://github.com/facebook/react-native/issues/15810#issuecomment-329940107 */
|
||||
const mockNativeModules = {
|
||||
AlertManager: {
|
||||
alertWithArgs: jest.fn(),
|
||||
},
|
||||
AppState: {
|
||||
addEventListener: jest.fn(),
|
||||
},
|
||||
AsyncLocalStorage: {
|
||||
multiGet: jest.fn((keys, callback) => process.nextTick(() => callback(null, []))),
|
||||
multiSet: jest.fn((entries, callback) => process.nextTick(() => callback(null))),
|
||||
multiRemove: jest.fn((keys, callback) => process.nextTick(() => callback(null))),
|
||||
multiMerge: jest.fn((entries, callback) => process.nextTick(() => callback(null))),
|
||||
clear: jest.fn(callback => process.nextTick(() => callback(null))),
|
||||
getAllKeys: jest.fn(callback => process.nextTick(() => callback(null, []))),
|
||||
},
|
||||
BuildInfo: {
|
||||
appVersion: '0',
|
||||
buildVersion: '0',
|
||||
},
|
||||
Clipboard: {
|
||||
setString: jest.fn(),
|
||||
},
|
||||
DataManager: {
|
||||
queryData: jest.fn(),
|
||||
},
|
||||
DeviceInfo: {
|
||||
Dimensions: {
|
||||
window: {
|
||||
fontScale: 2,
|
||||
height: 1334,
|
||||
scale: 2,
|
||||
width: 750,
|
||||
},
|
||||
},
|
||||
},
|
||||
FacebookSDK: {
|
||||
login: jest.fn(),
|
||||
logout: jest.fn(),
|
||||
queryGraphPath: jest.fn((path, method, params, callback) => callback()),
|
||||
},
|
||||
FbRelayNativeAdapter: {
|
||||
updateCLC: jest.fn(),
|
||||
},
|
||||
GraphPhotoUpload: {
|
||||
upload: jest.fn(),
|
||||
},
|
||||
I18n: {
|
||||
translationsDictionary: JSON.stringify({
|
||||
'Good bye, {name}!|Bye message': '\u{00A1}Adi\u{00F3}s {name}!',
|
||||
}),
|
||||
},
|
||||
ImageLoader: {
|
||||
getSize: jest.fn(
|
||||
(url) => new Promise(() => ({width: 320, height: 240}))
|
||||
),
|
||||
prefetchImage: jest.fn(),
|
||||
},
|
||||
ImageViewManager: {
|
||||
getSize: jest.fn(
|
||||
(uri, success) => process.nextTick(() => success(320, 240))
|
||||
),
|
||||
prefetchImage: jest.fn(),
|
||||
},
|
||||
KeyboardObserver: {
|
||||
addListener: jest.fn(),
|
||||
removeListeners: jest.fn(),
|
||||
},
|
||||
Linking: {
|
||||
openURL: jest.fn(),
|
||||
canOpenURL: jest.fn(
|
||||
() => new Promise((resolve) => resolve(true))
|
||||
),
|
||||
addEventListener: jest.fn(),
|
||||
getInitialURL: jest.fn(
|
||||
() => new Promise((resolve) => resolve())
|
||||
),
|
||||
removeEventListener: jest.fn(),
|
||||
},
|
||||
LocationObserver: {
|
||||
getCurrentPosition: jest.fn(),
|
||||
startObserving: jest.fn(),
|
||||
stopObserving: jest.fn(),
|
||||
},
|
||||
ModalFullscreenViewManager: {},
|
||||
NetInfo: {
|
||||
fetch: jest.fn(
|
||||
() => new Promise((resolve) => resolve())
|
||||
),
|
||||
addEventListener: jest.fn(),
|
||||
isConnected: {
|
||||
fetch: jest.fn(
|
||||
() => new Promise((resolve) => resolve())
|
||||
),
|
||||
addEventListener: jest.fn(),
|
||||
},
|
||||
},
|
||||
Networking: {
|
||||
sendRequest: jest.fn(),
|
||||
abortRequest: jest.fn(),
|
||||
addListener: jest.fn(),
|
||||
removeListeners: jest.fn(),
|
||||
},
|
||||
PushNotificationManager: {
|
||||
presentLocalNotification: jest.fn(),
|
||||
scheduleLocalNotification: jest.fn(),
|
||||
cancelAllLocalNotifications: jest.fn(),
|
||||
removeAllDeliveredNotifications: jest.fn(),
|
||||
getDeliveredNotifications: jest.fn(callback => process.nextTick(() => [])),
|
||||
removeDeliveredNotifications: jest.fn(),
|
||||
setApplicationIconBadgeNumber: jest.fn(),
|
||||
getApplicationIconBadgeNumber: jest.fn(callback => process.nextTick(() => callback(0))),
|
||||
cancelLocalNotifications: jest.fn(),
|
||||
getScheduledLocalNotifications: jest.fn(callback => process.nextTick(() => callback())),
|
||||
requestPermissions: jest.fn(() => Promise.resolve({alert: true, badge: true, sound: true})),
|
||||
abandonPermissions: jest.fn(),
|
||||
checkPermissions: jest.fn(callback => process.nextTick(() => callback({alert: true, badge: true, sound: true}))),
|
||||
getInitialNotification: jest.fn(() => Promise.resolve(null)),
|
||||
addListener: jest.fn(),
|
||||
removeListeners: jest.fn(),
|
||||
},
|
||||
SourceCode: {
|
||||
scriptURL: null,
|
||||
},
|
||||
StatusBarManager: {
|
||||
setColor: jest.fn(),
|
||||
setStyle: jest.fn(),
|
||||
setHidden: jest.fn(),
|
||||
setNetworkActivityIndicatorVisible: jest.fn(),
|
||||
setBackgroundColor: jest.fn(),
|
||||
setTranslucent: jest.fn(),
|
||||
},
|
||||
Timing: {
|
||||
createTimer: jest.fn(),
|
||||
deleteTimer: jest.fn(),
|
||||
},
|
||||
UIManager: {
|
||||
AndroidViewPager: {
|
||||
Commands: {
|
||||
setPage: jest.fn(),
|
||||
setPageWithoutAnimation: jest.fn(),
|
||||
},
|
||||
},
|
||||
blur: jest.fn(),
|
||||
createView: jest.fn(),
|
||||
dispatchViewManagerCommand: jest.fn(),
|
||||
focus: jest.fn(),
|
||||
setChildren: jest.fn(),
|
||||
manageChildren: jest.fn(),
|
||||
updateView: jest.fn(),
|
||||
removeSubviewsFromContainerWithID: jest.fn(),
|
||||
replaceExistingNonRootView: jest.fn(),
|
||||
customBubblingEventTypes: {},
|
||||
customDirectEventTypes: {},
|
||||
AndroidTextInput: {
|
||||
Commands: {},
|
||||
},
|
||||
ModalFullscreenView: {
|
||||
Constants: {},
|
||||
},
|
||||
ScrollView: {
|
||||
Constants: {},
|
||||
},
|
||||
View: {
|
||||
Constants: {},
|
||||
},
|
||||
},
|
||||
BlobModule: {
|
||||
BLOB_URI_SCHEME: 'content',
|
||||
BLOB_URI_HOST: null,
|
||||
enableBlobSupport: jest.fn(),
|
||||
disableBlobSupport: jest.fn(),
|
||||
createFromParts: jest.fn(),
|
||||
sendBlob: jest.fn(),
|
||||
release: jest.fn(),
|
||||
},
|
||||
WebSocketModule: {
|
||||
connect: jest.fn(),
|
||||
send: jest.fn(),
|
||||
sendBinary: jest.fn(),
|
||||
ping: jest.fn(),
|
||||
close: jest.fn(),
|
||||
addListener: jest.fn(),
|
||||
removeListeners: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
||||
Object.keys(mockNativeModules).forEach(module => {
|
||||
try {
|
||||
jest.doMock(module, () => mockNativeModules[module]); // needed by FacebookSDK-test
|
||||
} catch (e) {
|
||||
jest.doMock(module, () => mockNativeModules[module], {virtual: true});
|
||||
}
|
||||
});
|
||||
|
||||
jest.mock('Linking', () => ({
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
openURL: jest.genMockFn().mockReturnValue(Promise.resolve()),
|
||||
canOpenURL: jest.genMockFn().mockReturnValue(Promise.resolve()),
|
||||
getInitialURL: jest.genMockFn().mockReturnValue(Promise.resolve()),
|
||||
jest.doMock('tipsi-stripe', () => ({
|
||||
init: jest.fn(),
|
||||
}));
|
||||
+25
-15
@@ -6,30 +6,40 @@
|
||||
"start": "node node_modules/react-native/local-cli/cli.js start",
|
||||
"test": "jest",
|
||||
"emulator": "emulator -avd $(emulator -list-avds | head)&",
|
||||
"build-android": "cd android && ./gradlew assembleRelease"
|
||||
"build-android": "cd android && ./gradlew assembleRelease",
|
||||
"release-android": "cd android && fastlane beta"
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo-cache-inmemory": "^1.1.0",
|
||||
"apollo-client": "^2.0.2",
|
||||
"apollo-link-http": "^1.1.0",
|
||||
"email-validator": "^1.1.1",
|
||||
"graphql": "^0.11.7",
|
||||
"graphql-tag": "^2.5.0",
|
||||
"moment": "^2.19.1",
|
||||
"native-base": "^2.3.2",
|
||||
"native-base": "^2.3.3",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "16.0.0-beta.5",
|
||||
"react-native": "0.49.1",
|
||||
"react": "16.0.0",
|
||||
"react-apollo": "^2.0.0",
|
||||
"react-native": "0.50.3",
|
||||
"react-native-confetti": "^0.0.6",
|
||||
"react-native-config": "^0.6.1",
|
||||
"react-native-htmlview": "^0.12.0",
|
||||
"react-native-sentry": "^0.23.2",
|
||||
"react-navigation": "^1.0.0-beta.11",
|
||||
"react-native-config": "^0.10.0",
|
||||
"react-native-htmlview": "^0.12.1",
|
||||
"react-native-sentry": "^0.30.2",
|
||||
"react-native-vector-icons": "~4.4.2",
|
||||
"react-navigation": "^1.0.0-beta.19",
|
||||
"react-redux": "^5.0.6",
|
||||
"redux": "^3.7.2",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-persist": "^4.9.1",
|
||||
"redux-thunk": "^2.2.0"
|
||||
"redux-persist": "^4.10.2",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"tipsi-stripe": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-jest": "20.0.3",
|
||||
"babel-preset-react-native": "1.9.2",
|
||||
"jest": "20.0.4",
|
||||
"react-test-renderer": "16.0.0-alpha.12"
|
||||
"babel-jest": "21.2.0",
|
||||
"jest": "21.2.1",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-test-renderer": "16.1.1"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "react-native",
|
||||
@@ -37,7 +47,7 @@
|
||||
"<rootDir>/jest/setup.js"
|
||||
],
|
||||
"transformIgnorePatterns": [
|
||||
"node_modules/(?!(jest-)?react-native|react-clone-referenced-element|react-navigation|native-base|@shoutem)"
|
||||
"node_modules/(?!(jest-)?react-native|react-clone-referenced-element|react-navigation|native-base|@shoutem|tipsi-stripe)"
|
||||
]
|
||||
}
|
||||
}
|
||||
+19
-5
@@ -1,24 +1,38 @@
|
||||
import Dusken from "./Dusken";
|
||||
import React, {Component} from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { createStore, applyMiddleware } from 'redux';
|
||||
import {Provider} from 'react-redux';
|
||||
import {applyMiddleware, createStore} from 'redux';
|
||||
import logger from 'redux-logger';
|
||||
import thunk from 'redux-thunk';
|
||||
import {persistStore, autoRehydrate} from 'redux-persist'
|
||||
import {autoRehydrate, persistStore} from 'redux-persist'
|
||||
import {AsyncStorage} from 'react-native'
|
||||
import Config from 'react-native-config';
|
||||
import {ApolloClient} from 'apollo-client';
|
||||
import {HttpLink} from 'apollo-link-http';
|
||||
import {InMemoryCache} from 'apollo-cache-inmemory';
|
||||
import {ApolloProvider} from "react-apollo";
|
||||
|
||||
import Dusken from "./Dusken";
|
||||
import duskenApp from "./reducers";
|
||||
|
||||
|
||||
let store = createStore(
|
||||
duskenApp,
|
||||
applyMiddleware(...[logger, thunk]),
|
||||
autoRehydrate()
|
||||
);
|
||||
|
||||
const apolloClient = new ApolloClient({
|
||||
link: new HttpLink({uri: `${Config.DUSKEN_API_URL}/api/graphql/`}),
|
||||
cache: new InMemoryCache()
|
||||
});
|
||||
|
||||
export default class App extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Dusken />
|
||||
<ApolloProvider client={apolloClient}>
|
||||
<Dusken />
|
||||
</ApolloProvider>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
||||
+9
-46
@@ -1,52 +1,15 @@
|
||||
import React from 'react';
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from "react-redux";
|
||||
import {Platform} from 'react-native';
|
||||
import {TabNavigator, StackNavigator} from "react-navigation";
|
||||
|
||||
import AboutScreen from "./screens/AboutScreen";
|
||||
import EventDetailScreen from "./screens/EventDetailScreen";
|
||||
import EventListScreen from "./screens/EventListScreen";
|
||||
import LoginScreen from "./screens/LoginScreen";
|
||||
import MembershipScreen from "./screens/MembershipScreen";
|
||||
import {Root} from 'native-base';
|
||||
import DuskenNavigation from "./navigation";
|
||||
|
||||
|
||||
/* Navigation */
|
||||
const tabBarRoutes = {
|
||||
EventList: { screen: EventListScreen },
|
||||
Membership: { screen: MembershipScreen },
|
||||
About: { screen: AboutScreen },
|
||||
};
|
||||
|
||||
const tabBarOptions = {
|
||||
tabBarPosition: 'bottom',
|
||||
tabBarOptions: {
|
||||
style: {
|
||||
backgroundColor: "#fff"
|
||||
},
|
||||
indicatorStyle: {
|
||||
backgroundColor: "#f58220"
|
||||
},
|
||||
activeTintColor: '#f58220',
|
||||
inactiveTintColor: '#333333',
|
||||
showIcon: true,
|
||||
labelStyle: {
|
||||
fontSize: 10,
|
||||
marginBottom: 0,
|
||||
...Platform.select({
|
||||
android: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
}),
|
||||
},
|
||||
class DuskenContainer extends Component {
|
||||
render() {
|
||||
return (<Root>
|
||||
<DuskenNavigation/>
|
||||
</Root>)
|
||||
}
|
||||
};
|
||||
|
||||
const tabNav = TabNavigator(tabBarRoutes, tabBarOptions);
|
||||
|
||||
const DuskenContainer = StackNavigator({
|
||||
Root: { screen: tabNav },
|
||||
Login: { screen: LoginScreen },
|
||||
EventDetail: { screen: EventDetailScreen },
|
||||
});
|
||||
}
|
||||
|
||||
export default connect()(DuskenContainer);
|
||||
+52
-70
@@ -1,5 +1,3 @@
|
||||
import Config from 'react-native-config';
|
||||
|
||||
const LOGIN_REQUEST = 'LOGIN_REQUEST';
|
||||
const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
|
||||
const LOGIN_FAILURE = 'LOGIN_FAILURE';
|
||||
@@ -7,6 +5,12 @@ const LOGOUT = 'LOGOUT';
|
||||
const USER_DATA_REQUEST = 'USER_DATA_REQUEST';
|
||||
const USER_DATA_SUCCESS = 'USER_DATA_SUCCESS';
|
||||
const USER_DATA_FAILURE = 'USER_DATA_FAILURE';
|
||||
const REGISTER_USER_REQUEST = 'REGISTER_USER_REQUEST';
|
||||
const REGISTER_USER_SUCCESS = 'REGISTER_USER_SUCCESS';
|
||||
const REGISTER_USER_FAILURE = 'REGISTER_USER_FAILURE';
|
||||
const MEMBERSHIP_CHARGE_REQUEST = 'MEMBERSHIP_CHARGE_REQUEST';
|
||||
const MEMBERSHIP_CHARGE_SUCCESS = 'MEMBERSHIP_CHARGE_SUCCESS';
|
||||
const MEMBERSHIP_CHARGE_FAILURE = 'MEMBERSHIP_CHARGE_FAILURE';
|
||||
|
||||
function loginRequest() {
|
||||
return {
|
||||
@@ -55,6 +59,45 @@ function userDataFailure(userError) {
|
||||
}
|
||||
}
|
||||
|
||||
function registerUserRequest() {
|
||||
return {
|
||||
type: REGISTER_USER_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
function registerUserSuccess(data) {
|
||||
return {
|
||||
type: REGISTER_USER_SUCCESS,
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
function registerUserFailure(registerError) {
|
||||
return {
|
||||
type: REGISTER_USER_FAILURE,
|
||||
registerError
|
||||
}
|
||||
}
|
||||
function membershipChargeRequest() {
|
||||
return {
|
||||
type: MEMBERSHIP_CHARGE_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
function membershipChargeSuccess(data) {
|
||||
return {
|
||||
type: MEMBERSHIP_CHARGE_SUCCESS,
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
function membershipChargeFailure(chargeError) {
|
||||
return {
|
||||
type: MEMBERSHIP_CHARGE_FAILURE,
|
||||
chargeError
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
LOGIN_REQUEST, loginRequest,
|
||||
LOGIN_SUCCESS, loginSuccess,
|
||||
@@ -63,71 +106,10 @@ export {
|
||||
USER_DATA_REQUEST, userDataRequest,
|
||||
USER_DATA_SUCCESS, userDataSuccess,
|
||||
USER_DATA_FAILURE, userDataFailure,
|
||||
};
|
||||
|
||||
export function requestLogin(username, password) {
|
||||
return (dispatch) => {
|
||||
// We are now logging in
|
||||
dispatch(loginRequest());
|
||||
const apiURL = Config.DUSKEN_API_URL;
|
||||
return fetch(`${apiURL}/auth/obtain-token/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
'username': username,
|
||||
'password': password
|
||||
})
|
||||
})
|
||||
.then(response => response.json().then(json => ({ json, response })))
|
||||
.then(({json, response}) => {
|
||||
if (response.ok === false) {
|
||||
return Promise.reject(json)
|
||||
}
|
||||
return json
|
||||
})
|
||||
.then(
|
||||
data => {
|
||||
dispatch(loginSuccess(username, data.token))
|
||||
},
|
||||
data => {
|
||||
console.log(data);
|
||||
dispatch(loginFailure(data || {'non_field_errors': ['Kunne ikke logge inn, prøv igjen']}))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function requestUserData(token) {
|
||||
return (dispatch) => {
|
||||
// We are now fetching user data
|
||||
dispatch(userDataRequest());
|
||||
|
||||
const apiURL = Config.DUSKEN_API_URL;
|
||||
return fetch(`${apiURL}/api/me/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Token ' + token
|
||||
}
|
||||
})
|
||||
.then(response => response.json().then(json => ({ json, response })))
|
||||
.then(({json, response}) => {
|
||||
if (response.ok === false) {
|
||||
return Promise.reject(json)
|
||||
}
|
||||
return json
|
||||
})
|
||||
.then(
|
||||
data => {
|
||||
dispatch(userDataSuccess(data))
|
||||
},
|
||||
data => {
|
||||
dispatch(userDataFailure('Det funka ikke :-('))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
REGISTER_USER_REQUEST, registerUserRequest,
|
||||
REGISTER_USER_SUCCESS, registerUserSuccess,
|
||||
REGISTER_USER_FAILURE, registerUserFailure,
|
||||
MEMBERSHIP_CHARGE_REQUEST, membershipChargeRequest,
|
||||
MEMBERSHIP_CHARGE_SUCCESS, membershipChargeSuccess,
|
||||
MEMBERSHIP_CHARGE_FAILURE, membershipChargeFailure,
|
||||
};
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
import Config from 'react-native-config';
|
||||
|
||||
import {
|
||||
loginFailure, loginRequest, loginSuccess,
|
||||
registerUserFailure, registerUserRequest, registerUserSuccess,
|
||||
userDataFailure, userDataRequest, userDataSuccess,
|
||||
membershipChargeFailure, membershipChargeRequest, membershipChargeSuccess,
|
||||
} from "./actions";
|
||||
|
||||
export function requestLogin(username, password) {
|
||||
return (dispatch) => {
|
||||
// We are now logging in
|
||||
dispatch(loginRequest());
|
||||
|
||||
return fetch(`${Config.DUSKEN_API_URL}/auth/obtain-token/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
'username': username,
|
||||
'password': password
|
||||
})
|
||||
})
|
||||
.then(response => response.json().then(json => ({ json, response })))
|
||||
.then(({json, response}) => {
|
||||
if (response.ok === false) {
|
||||
return Promise.reject(json)
|
||||
}
|
||||
return json
|
||||
})
|
||||
.then(
|
||||
data => {
|
||||
dispatch(loginSuccess(username, data.token))
|
||||
},
|
||||
data => {
|
||||
console.log(data);
|
||||
dispatch(loginFailure(data || {'non_field_errors': ['Kunne ikke logge inn, prøv igjen']}))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function requestUserData(auth_token) {
|
||||
return (dispatch) => {
|
||||
// We are now fetching user data
|
||||
dispatch(userDataRequest());
|
||||
|
||||
return fetch(`${Config.DUSKEN_API_URL}/api/me/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Token ${auth_token}`
|
||||
}
|
||||
})
|
||||
.then(response => response.json().then(json => ({ json, response })))
|
||||
.then(({json, response}) => {
|
||||
if (response.ok === false) {
|
||||
return Promise.reject(json)
|
||||
}
|
||||
return json
|
||||
})
|
||||
.then(
|
||||
data => {
|
||||
dispatch(userDataSuccess(data))
|
||||
},
|
||||
data => {
|
||||
dispatch(userDataFailure(data || {'non_field_errors': ['Kunne ikke hente brukerdata']}))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function requestRegisterUser(firstName, lastName, email, phoneNumber, password) {
|
||||
return (dispatch) => {
|
||||
dispatch(registerUserRequest());
|
||||
|
||||
return fetch(`${Config.DUSKEN_API_URL}/api/user/register/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
'first_name': firstName,
|
||||
'last_name': lastName,
|
||||
'email': email,
|
||||
'phone_number': phoneNumber,
|
||||
'password': password
|
||||
})
|
||||
})
|
||||
.then(response => response.json().then(json => ({ json, response })))
|
||||
.then(({json, response}) => {
|
||||
if (response.ok === false) {
|
||||
return Promise.reject(json)
|
||||
}
|
||||
return json
|
||||
})
|
||||
.then(
|
||||
data => {
|
||||
dispatch(registerUserSuccess(data))
|
||||
},
|
||||
data => {
|
||||
dispatch(registerUserFailure(data || {'non_field_errors': ['Kunne ikke registrere bruker, prøv igjen']}))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function requestMembershipCharge(auth_token, stripe_token, membership_type) {
|
||||
return (dispatch) => {
|
||||
dispatch(membershipChargeRequest());
|
||||
|
||||
return fetch(`${Config.DUSKEN_API_URL}/api/membership/charge/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Token ${auth_token}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
'stripe_token': stripe_token,
|
||||
'membership_type': membership_type,
|
||||
'payment_method': 'app',
|
||||
})
|
||||
})
|
||||
.then(response => response.json().then(json => ({ json, response })))
|
||||
.then(({json, response}) => {
|
||||
if (response.ok === false) {
|
||||
return Promise.reject(json)
|
||||
}
|
||||
return json
|
||||
})
|
||||
.then(
|
||||
data => {
|
||||
dispatch(membershipChargeSuccess(data))
|
||||
},
|
||||
data => {
|
||||
dispatch(membershipChargeFailure(data || {'non_field_errors': ['Kunne ikke belaste kort, prøv igjen']}))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {Text, ScrollView, View, Platform, StyleSheet, Image, Linking, TouchableO
|
||||
// import HTMLView from 'react-native-htmlview';
|
||||
|
||||
import {Button, Text as NBText, Icon} from 'native-base';
|
||||
import theme from "../../theme";
|
||||
|
||||
const CHATEAU_NEUF_ADDRESS = 'Det Norske Studentersamfund, Slemdalsveien 15, 0369 Oslo';
|
||||
|
||||
@@ -125,24 +126,7 @@ const styles = StyleSheet.create({
|
||||
paddingBottom: 10,
|
||||
lineHeight: 25,
|
||||
},
|
||||
card: {
|
||||
borderColor: '#e1e8ee',
|
||||
borderWidth: 1,
|
||||
...Platform.select({
|
||||
ios: {
|
||||
shadowColor: 'rgba(0,0,0, .2)',
|
||||
shadowOffset: {height: 0, width: 0},
|
||||
shadowOpacity: 1,
|
||||
shadowRadius: 1,
|
||||
},
|
||||
android: {
|
||||
elevation: 1,
|
||||
},
|
||||
}),
|
||||
padding: 8,
|
||||
margin: 8,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
card: theme.card,
|
||||
featuredImage: {
|
||||
height: 230,
|
||||
width: null,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { Component } from 'react';
|
||||
import {Linking, StyleSheet, ScrollView, Text, Platform, View, Image, TouchableHighlight,
|
||||
TouchableOpacity} from "react-native";
|
||||
import {Linking, StyleSheet, ScrollView, Text, Platform, View, Image, TouchableOpacity} from "react-native";
|
||||
import HTMLView from 'react-native-htmlview';
|
||||
import moment from "moment";
|
||||
import {Button, Icon, Text as NBText} from "native-base";
|
||||
import {Icon} from "native-base";
|
||||
import theme from "../../theme";
|
||||
|
||||
moment.locale('nb');
|
||||
|
||||
@@ -172,7 +172,7 @@ export default class EventDetail extends Component {
|
||||
{/* Date and title */}
|
||||
<View style={styles.dateAndTitle}>
|
||||
<View style={styles.dateContainer}>
|
||||
<View style={styles.dateCard}>
|
||||
<View style={[styles.card, styles.dateCard]}>
|
||||
<Text style={styles.day}>{this._formatDay(item.start_time)}</Text>
|
||||
<Text style={styles.month}>{this._formatMonth(item.start_time)}</Text>
|
||||
{this.showYear()}
|
||||
@@ -222,24 +222,7 @@ const styles = StyleSheet.create({
|
||||
fontWeight: 'bold',
|
||||
color: '#000',
|
||||
},
|
||||
card: {
|
||||
borderColor: '#e1e8ee',
|
||||
borderWidth: 1,
|
||||
...Platform.select({
|
||||
ios: {
|
||||
shadowColor: 'rgba(0,0,0, .2)',
|
||||
shadowOffset: {height: 0, width: 0},
|
||||
shadowOpacity: 1,
|
||||
shadowRadius: 1,
|
||||
},
|
||||
android: {
|
||||
elevation: 1,
|
||||
},
|
||||
}),
|
||||
padding: 8,
|
||||
margin: 8,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
card: theme.card,
|
||||
image: {
|
||||
height: 260,
|
||||
width: null
|
||||
@@ -275,20 +258,8 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
},
|
||||
dateCard: {
|
||||
borderColor: '#e1e8ee',
|
||||
borderWidth: 1,
|
||||
...Platform.select({
|
||||
ios: {
|
||||
shadowColor: 'rgba(0,0,0, .2)',
|
||||
shadowOffset: {height: 0, width: 0},
|
||||
shadowOpacity: 2,
|
||||
shadowRadius: 2,
|
||||
},
|
||||
android: {
|
||||
elevation: 1,
|
||||
},
|
||||
}),
|
||||
backgroundColor: '#fff',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
paddingBottom: 6,
|
||||
width: 62,
|
||||
},
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {StyleSheet, ActivityIndicator, View, SectionList} from "react-native";
|
||||
import {Card, ListItem, CardItem, Body, Text as Text, Left, Right, Icon, Button, Content} from 'native-base';
|
||||
import {StyleSheet, View, SectionList, Platform} from "react-native";
|
||||
import {Card, ListItem, CardItem, Body, Text as Text, Left, Right, Icon, Button, Content, Spinner} from 'native-base';
|
||||
import React, { Component } from 'react';
|
||||
import moment from "moment";
|
||||
import 'moment/locale/nb';
|
||||
import theme from "../../theme";
|
||||
|
||||
moment.locale('nb');
|
||||
|
||||
@@ -20,9 +21,9 @@ export default class EventList extends Component {
|
||||
);
|
||||
|
||||
_renderSectionHeader = ({section}) => {
|
||||
return (<ListItem style={[styles.listItem, {paddingBottom: 8}]}>
|
||||
return (<ListItem style={styles.sectionHeader}>
|
||||
<Body>
|
||||
<Text style={styles.listItemSectionTitle}>{section.title}</Text>
|
||||
<Text style={styles.sectionTitle}>{section.title}</Text>
|
||||
</Body>
|
||||
</ListItem>);
|
||||
};
|
||||
@@ -33,7 +34,7 @@ export default class EventList extends Component {
|
||||
}
|
||||
|
||||
return (<View style={{paddingVertical: 20}}>
|
||||
<ActivityIndicator animating size="large" />
|
||||
<Spinner color="#f58220"/>
|
||||
</View>);
|
||||
};
|
||||
|
||||
@@ -71,7 +72,8 @@ export default class EventList extends Component {
|
||||
onEndReachedThreshould={10}
|
||||
initialNumToRender={10}
|
||||
ListFooterComponent={this._renderFooter}
|
||||
style={styles.list}
|
||||
style={[styles.card, styles.list]}
|
||||
ListHeaderComponent={() => { return <View style={styles.listHeader}/> }}
|
||||
/>);
|
||||
}
|
||||
}
|
||||
@@ -79,6 +81,7 @@ export default class EventList extends Component {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
listItem: {
|
||||
backgroundColor: 'white',
|
||||
marginLeft: 0
|
||||
},
|
||||
listItemTitle: {
|
||||
@@ -88,15 +91,31 @@ const styles = StyleSheet.create({
|
||||
fontSize: 14,
|
||||
color: '#666'
|
||||
},
|
||||
listItemSectionTitle: {
|
||||
fontSize: 14,
|
||||
sectionHeader: {
|
||||
backgroundColor: 'white',
|
||||
marginLeft: 0,
|
||||
...Platform.select({
|
||||
'ios': {marginBottom: -8},
|
||||
}),
|
||||
paddingBottom: 0,
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
loadingText: {
|
||||
textAlign: 'center',
|
||||
paddingBottom: 8
|
||||
},
|
||||
card: theme.card,
|
||||
list: {
|
||||
backgroundColor: 'white'
|
||||
padding: 0,
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
listHeader: {
|
||||
paddingTop: 8,
|
||||
}
|
||||
});
|
||||
@@ -3,6 +3,7 @@ import {Linking, StyleSheet, View, Platform} from 'react-native';
|
||||
import {Container, Header, Content, Form, Item, Input, Label, Spinner, Button, Text,
|
||||
Icon} from 'native-base';
|
||||
import Config from 'react-native-config';
|
||||
import theme from "../../theme";
|
||||
|
||||
export default class Login extends Component {
|
||||
constructor(props) {
|
||||
@@ -157,22 +158,5 @@ const styles = StyleSheet.create({
|
||||
textAlign: 'center',
|
||||
color: 'red',
|
||||
},
|
||||
card: {
|
||||
borderColor: '#e1e8ee',
|
||||
borderWidth: 1,
|
||||
...Platform.select({
|
||||
ios: {
|
||||
shadowColor: 'rgba(0,0,0, .2)',
|
||||
shadowOffset: {height: 0, width: 0},
|
||||
shadowOpacity: 1,
|
||||
shadowRadius: 1,
|
||||
},
|
||||
android: {
|
||||
elevation: 1,
|
||||
},
|
||||
}),
|
||||
padding: 8,
|
||||
margin: 8,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
card: theme.card,
|
||||
});
|
||||
@@ -1,42 +1,27 @@
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from "react-redux";
|
||||
import Login from "./Login";
|
||||
import {requestLogin} from "../../actions";
|
||||
import {requestLogin} from "../../api";
|
||||
|
||||
class LoginContainer extends Component {
|
||||
constructor(state) {
|
||||
super(state);
|
||||
this.state = {
|
||||
isAuthenticated: false,
|
||||
isLoggingIn: false,
|
||||
loginError: null,
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.state.isAuthenticated !== nextProps.isAuthenticated) {
|
||||
if (this.props.isAuthenticated !== nextProps.isAuthenticated) {
|
||||
if (nextProps.isAuthenticated) {
|
||||
this.props.onLogin();
|
||||
}
|
||||
}
|
||||
if (this.state.isLoggingIn !== nextProps.isLoggingIn) {
|
||||
this.setState({isLoggingIn: nextProps.isLoggingIn})
|
||||
}
|
||||
if (this.state.loginError !== nextProps.loginError) {
|
||||
this.setState({loginError: nextProps.loginError})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Login {...this.state} requestLogin={this.props.requestLogin}/>
|
||||
return <Login {...this.props} />
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
(state) => ({
|
||||
isAuthenticated: state.isAuthenticated,
|
||||
isLoggingIn: state.isLoggingIn,
|
||||
loginError: state.loginError,
|
||||
(store) => ({
|
||||
isAuthenticated: store.isAuthenticated,
|
||||
isLoggingIn: store.isLoggingIn,
|
||||
loginError: store.loginError,
|
||||
}),
|
||||
{requestLogin}
|
||||
)(LoginContainer);
|
||||
@@ -1,17 +1,27 @@
|
||||
import React, {Component} from 'react';
|
||||
import {ScrollView, Text, View, Linking, StyleSheet, Platform} from "react-native";
|
||||
import {Button, Text as NBText} from "native-base";
|
||||
import Config from 'react-native-config';
|
||||
import {ScrollView, Text, View, StyleSheet} from "react-native";
|
||||
import {Button, Text as NBText, Spinner} from "native-base";
|
||||
|
||||
import theme from "../../theme";
|
||||
|
||||
|
||||
export default class Membership extends Component {
|
||||
render() {
|
||||
if (this.props.isFetchingUserData) {
|
||||
return (
|
||||
<View style={styles.card}>
|
||||
<Spinner color="#f58220"/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollView>
|
||||
<View style={styles.card}>
|
||||
<Text style={styles.headerTitle}>Hei 👋</Text>
|
||||
<Text style={styles.paragraph}>Her kan du bli medlem i Det Norske Studentersamfund - Chateau Neuf og ha medlemsbeviset ditt på telefonen</Text>
|
||||
<View style={styles.button}>
|
||||
<Button onPress={() => { Linking.openURL(Config.DUSKEN_PURCHASE_URL); } } full><NBText>Bli medlem</NBText></Button>
|
||||
<Button onPress={this.props.onRegisterPress} full><NBText>Bli medlem</NBText></Button>
|
||||
</View>
|
||||
<Text style={styles.header}>Hva får jeg?</Text>
|
||||
<Text style={[styles.paragraph, {textAlign: 'left', paddingLeft: 4}]}>
|
||||
@@ -22,38 +32,18 @@ export default class Membership extends Component {
|
||||
- Mulighet til å delta i landets eldste studentdemokrati</Text>
|
||||
<Text style={styles.em}>Allerede medlem?</Text>
|
||||
<View style={styles.button}>
|
||||
<Button onPress={this.onLoginPress} full><NBText>Logg inn</NBText></Button>
|
||||
<Button onPress={this.props.onLoginPress} full><NBText>Logg inn</NBText></Button>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
)
|
||||
};
|
||||
|
||||
onLoginPress = () => {
|
||||
this.props.onLoginPress();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: {
|
||||
borderColor: '#e1e8ee',
|
||||
borderWidth: 1,
|
||||
...Platform.select({
|
||||
ios: {
|
||||
shadowColor: 'rgba(0,0,0, .2)',
|
||||
shadowOffset: {height: 0, width: 0},
|
||||
shadowOpacity: 1,
|
||||
shadowRadius: 1,
|
||||
},
|
||||
android: {
|
||||
elevation: 1,
|
||||
},
|
||||
}),
|
||||
padding: 8,
|
||||
margin: 8,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
card: theme.card,
|
||||
paragraph: {
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
import React from 'react';
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from "react-redux";
|
||||
|
||||
import Membership from "./Membership";
|
||||
import MembershipProof from "./MembershipProof";
|
||||
import { requestUserData, logout } from "../../actions";
|
||||
import ProofContainer from "./ProofContainer";
|
||||
import { logout } from "../../actions";
|
||||
import {requestUserData} from "../../api";
|
||||
|
||||
class MembershipContainer extends React.Component {
|
||||
class MembershipContainer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isAuthenticated: props.isAuthenticated,
|
||||
userToken: props.userToken,
|
||||
isFetchingUserData: props.isFetchingUserData,
|
||||
user: props.user,
|
||||
userToken: props.userToken,
|
||||
lastOrder: props.lastOrder,
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if(this.state.isAuthenticated !== nextProps.isAuthenticated) {
|
||||
this.setState({isAuthenticated: nextProps.isAuthenticated})
|
||||
}
|
||||
if(this.state.userToken !== nextProps.userToken) {
|
||||
this.setState({userToken: nextProps.userToken}, () => {
|
||||
if(nextProps.userToken) {
|
||||
@@ -29,8 +26,12 @@ class MembershipContainer extends React.Component {
|
||||
});
|
||||
|
||||
}
|
||||
if(this.state.user !== nextProps.user) {
|
||||
this.setState({user: nextProps.user})
|
||||
if(this.state.lastOrder !== nextProps.lastOrder) {
|
||||
this.setState({lastOrder: nextProps.lastOrder}, () => {
|
||||
if(nextProps.userToken) {
|
||||
this.fetchUser();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,29 +43,44 @@ class MembershipContainer extends React.Component {
|
||||
this.props.onLoginPress();
|
||||
};
|
||||
|
||||
onRegisterPress = () => {
|
||||
this.props.onRegisterPress();
|
||||
};
|
||||
|
||||
onLogoutPress = () => {
|
||||
this.props.logout();
|
||||
this.props.logoutNavigate();
|
||||
this.props.onLogoutPress();
|
||||
};
|
||||
|
||||
render() {
|
||||
if (this.state.user) {
|
||||
return <MembershipProof
|
||||
user={this.state.user}
|
||||
if (this.props.user) {
|
||||
return <ProofContainer
|
||||
user={this.props.user}
|
||||
isAuthenticated={this.props.isAuthenticated}
|
||||
userToken={this.state.userToken}
|
||||
fetchUser={this.fetchUser}
|
||||
onLogoutPress={this.onLogoutPress}
|
||||
/>;
|
||||
}
|
||||
return <Membership onLoginPress={this.onLoginPress}/>;
|
||||
return <Membership
|
||||
isFetchingUserData={this.props.isFetchingUserData}
|
||||
onLoginPress={this.onLoginPress}
|
||||
onRegisterPress={this.onRegisterPress}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
function storeToProps(store) {
|
||||
return {
|
||||
isAuthenticated: store.isAuthenticated,
|
||||
isFetchingUserData: store.isFetchingUserData,
|
||||
userToken: store.userToken,
|
||||
user: store.user,
|
||||
lastOrder: store.lastOrder
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
(state) => ({
|
||||
isAuthenticated: state.isAuthenticated,
|
||||
isFetchingUserData: state.isFetchingUserData,
|
||||
userToken: state.userToken,
|
||||
user: state.user,
|
||||
}),
|
||||
storeToProps,
|
||||
{ requestUserData, logout }
|
||||
)(MembershipContainer);
|
||||
@@ -1,27 +1,20 @@
|
||||
import React, {Component} from 'react';
|
||||
import {Image, Linking, StyleSheet, Platform, RefreshControl, TouchableOpacity, View} from "react-native";
|
||||
import {Button, Body, Card, CardItem, Text, Content} from 'native-base';
|
||||
import Config from 'react-native-config';
|
||||
import {Image, ScrollView, StyleSheet, Text, TouchableOpacity, View} from "react-native";
|
||||
import {Button, Text as NBText, Spinner} from 'native-base';
|
||||
import Confetti from 'react-native-confetti';
|
||||
|
||||
export default class MembershipProof extends Component {
|
||||
import theme from "../../theme";
|
||||
|
||||
export default class Proof extends Component {
|
||||
CONFETTI_TIMEOUT = 15000;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
user: props.user,
|
||||
refreshing: false,
|
||||
stopConfetti: false,
|
||||
}
|
||||
};
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if(this.state.user !== nextProps.user) {
|
||||
this.setState({user: nextProps.user})
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
if (this._confettiView && this.state.stopConfetti) {
|
||||
this._confettiView.stopConfetti();
|
||||
@@ -35,26 +28,6 @@ export default class MembershipProof extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
// fetchUser = () => {
|
||||
// this.props.fetchUser().then(() => {
|
||||
// this.setState({refreshing: false});
|
||||
// });
|
||||
// };
|
||||
|
||||
// _onRefresh() {
|
||||
// console.log('onRefresh')
|
||||
// this.setState({refreshing: true});
|
||||
// this.fetchUser()
|
||||
// }
|
||||
|
||||
// refreshControl() {
|
||||
// return (
|
||||
// <RefreshControl
|
||||
// refreshing={this.state.refreshing}
|
||||
// onRefresh={this._onRefresh.bind(this)}
|
||||
// />)
|
||||
// }
|
||||
|
||||
onMembershipPress = () => {
|
||||
this.setState({showConfetti: true}, () => {
|
||||
if(this._confettiView) {
|
||||
@@ -67,126 +40,137 @@ export default class MembershipProof extends Component {
|
||||
};
|
||||
|
||||
membershipValidTo() {
|
||||
if( !this.state.user.last_membership) {
|
||||
if( !this.props.user.last_membership) {
|
||||
return;
|
||||
}
|
||||
|
||||
let validTo = this.state.user.last_membership.end_date;
|
||||
if (this.state.user.last_membership.membership_type === 'lifelong') {
|
||||
let validTo = this.props.user.last_membership.end_date;
|
||||
if (this.props.user.last_membership.membership_type === 'lifelong') {
|
||||
validTo = 'Livsvarig'
|
||||
}
|
||||
|
||||
return (
|
||||
<CardItem>
|
||||
<View style={{alignItems: 'center', flex: 1}}>
|
||||
<Text>Gyldig til: </Text>
|
||||
<Text style={styles.validToValue}>{validTo}</Text>
|
||||
</View>
|
||||
</CardItem>
|
||||
<View style={{alignItems: 'center', flex: 1}}>
|
||||
<Text>Gyldig til: </Text>
|
||||
<Text style={styles.validToValue}>{validTo}</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
membershipStatus() {
|
||||
if (!this.state.user.is_member) {
|
||||
if ( !this.state.user.last_membership ) {
|
||||
return (
|
||||
<CardItem>
|
||||
<View style={styles.notMember}>
|
||||
<Text style={styles.notMemberText}>Ikke medlem</Text>
|
||||
</View>
|
||||
</CardItem>)
|
||||
if (!this.props.user.is_member) {
|
||||
if ( !this.props.user.last_membership ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return <View style={styles.expired}><Text style={styles.expiredText}>Utløpt</Text></View>
|
||||
return (
|
||||
<View style={styles.expired}>
|
||||
<Text style={styles.expiredText}>Utløpt</Text>
|
||||
</View>)
|
||||
}
|
||||
|
||||
let statusText = 'Medlem';
|
||||
if (this.state.user.is_volunteer) {
|
||||
statusText = 'Aktiv';
|
||||
}
|
||||
const statusText = this.props.user.is_volunteer ? 'Aktiv' : 'Medlem';
|
||||
|
||||
return (
|
||||
<CardItem>
|
||||
<View style={styles.membershipStatus}>
|
||||
<TouchableOpacity onPress={this.onMembershipPress} style={styles.valid}>
|
||||
<Text style={styles.validText}>{statusText}</Text>
|
||||
</TouchableOpacity>
|
||||
</CardItem>);
|
||||
</View>);
|
||||
}
|
||||
|
||||
purchaseButton() {
|
||||
if (this.state.user.is_member) {
|
||||
if (this.props.user.is_member) {
|
||||
return;
|
||||
}
|
||||
return <CardItem>
|
||||
<Body>
|
||||
|
||||
return (
|
||||
<View>
|
||||
{this.props.isChargingMembership && <Spinner color="#f58220"/>}
|
||||
<Button
|
||||
onPress={() => {
|
||||
Linking.openURL(Config.DUSKEN_PURCHASE_URL);
|
||||
}}
|
||||
onPress={this.props.onChargePress}
|
||||
full
|
||||
disabled={this.props.isChargingMembership || this.props.isLoadingMembershipType}
|
||||
style={styles.purchaseButton}
|
||||
>
|
||||
<Text>Kjøp medlemskap</Text>
|
||||
<NBText>{`Kjøp medlemskap (${this.props.membershipPrice} NOK)`}</NBText>
|
||||
</Button>
|
||||
</Body>
|
||||
</CardItem>
|
||||
<View style={styles.purchaseText}>
|
||||
<Text style={styles.purchaseTextInner}>Medlemskapet er gyldig i ett år</Text>
|
||||
</View>
|
||||
</View>)
|
||||
}
|
||||
|
||||
confetti() {
|
||||
if (this.state.user.is_member) {
|
||||
// FIXME: allmost infinite confetti. Are the animations paused when not visible, if not power hog?
|
||||
if (this.props.user.is_member) {
|
||||
// Confetti!!!!
|
||||
return <Confetti ref={(node) => this._confettiView = node} confettiCount={Number.MAX_SAFE_INTEGER} />
|
||||
}
|
||||
}
|
||||
|
||||
logo() {
|
||||
if (!this.state.user.is_member) {
|
||||
if (!this.props.user.is_member) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: URL to config
|
||||
return <Image
|
||||
style={{width: null, height: 100}}
|
||||
source={{uri: 'https://galtinn.neuf.no/static/dist/images/logo.png'}}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
return (
|
||||
<View style={{marginTop: 8}}>
|
||||
<Image
|
||||
style={{width: null, height: 100}}
|
||||
source={{uri: 'https://galtinn.neuf.no/static/dist/images/logo.png'}}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
</View>)
|
||||
}
|
||||
|
||||
fetchUser = () => {
|
||||
this.props.fetchUser()
|
||||
};
|
||||
chargeError() {
|
||||
if (!this.props.chargeError) {
|
||||
return;
|
||||
}
|
||||
|
||||
return <View><Text style={styles.errorMessage}>{this.props.chargeError}</Text></View>
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
<View>
|
||||
{this.confetti()}
|
||||
<Content style={{margin: 8}}>
|
||||
<Card>
|
||||
<ScrollView>
|
||||
<View style={[styles.card, {paddingVertical: 16}]}>
|
||||
{this.membershipName()}
|
||||
{this.logo()}
|
||||
{this.membershipStatus()}
|
||||
{this.chargeError()}
|
||||
{this.purchaseButton()}
|
||||
{this.membershipValidTo()}
|
||||
</Card>
|
||||
<Button onPress={this.props.onLogoutPress} style={styles.logoutButton} small>
|
||||
<Text>Logg ut</Text>
|
||||
</Button>
|
||||
</Content>
|
||||
</View>
|
||||
<View>
|
||||
<Button onPress={this.props.onLogoutPress} style={styles.logoutButton} small>
|
||||
<NBText>Logg ut</NBText>
|
||||
</Button>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
)
|
||||
};
|
||||
|
||||
membershipName() {
|
||||
let name = `${this.state.user.first_name} ${this.state.user.last_name}`;
|
||||
let name = `${this.props.user.first_name} ${this.props.user.last_name}`;
|
||||
if(name === ' ') {
|
||||
name = this.state.user.email;
|
||||
name = this.props.user.email;
|
||||
}
|
||||
return <CardItem>
|
||||
return <View>
|
||||
<Text style={styles.nameText}>{name}</Text>
|
||||
</CardItem>
|
||||
</View>
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: theme.card,
|
||||
membershipStatus: {
|
||||
marginVertical: 16,
|
||||
},
|
||||
nameText: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
@@ -208,7 +192,8 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: '#d9534f',
|
||||
flex: 1,
|
||||
marginHorizontal: -16,
|
||||
padding: 16
|
||||
padding: 16,
|
||||
marginVertical: 16,
|
||||
},
|
||||
expiredText: {
|
||||
color: 'white',
|
||||
@@ -237,4 +222,19 @@ const styles = StyleSheet.create({
|
||||
alignSelf: 'center',
|
||||
marginVertical: 20,
|
||||
},
|
||||
purchaseText: {
|
||||
alignItems: 'center'
|
||||
},
|
||||
purchaseTextInner: {
|
||||
fontStyle: 'italic',
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
paddingTop: 10,
|
||||
paddingBottom: 8
|
||||
},
|
||||
errorMessage: {
|
||||
paddingTop: 10,
|
||||
textAlign: 'center',
|
||||
color: theme.colors.danger
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,105 @@
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from "react-redux";
|
||||
import stripe from 'tipsi-stripe'
|
||||
import Config from 'react-native-config';
|
||||
import { graphql } from 'react-apollo';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import Proof from "./Proof";
|
||||
import {requestMembershipCharge} from "../../api";
|
||||
|
||||
|
||||
stripe.init({
|
||||
publishableKey: Config.STRIPE_PUBLISHABLE_KEY || '',
|
||||
});
|
||||
|
||||
|
||||
class ProofContainer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
refreshing: false,
|
||||
}
|
||||
}
|
||||
|
||||
getPrice(membershipTypes) {
|
||||
if (!membershipTypes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return membershipTypes[0].price / 100;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Proof
|
||||
{...this.state}
|
||||
user={this.props.user}
|
||||
isChargingMembership={this.props.isChargingMembership}
|
||||
isLoadingMembershipType={this.props.data.loading}
|
||||
chargeError={this.props.chargeError ? 'Kunne ikke belaste bankkortet, prøv igjen...' : ''}
|
||||
onChargePress={this.openStripe}
|
||||
onLogoutPress={this.props.onLogoutPress}
|
||||
membershipPrice={this.getPrice(this.props.data.membershipTypes)}
|
||||
/>
|
||||
}
|
||||
|
||||
openStripe = () => {
|
||||
const options = {
|
||||
prefilledInformation: {
|
||||
email: this.props.user.email,
|
||||
},
|
||||
smsAutofillDisabled: true,
|
||||
};
|
||||
|
||||
const membershipTypeSlug = this.props.data.membershipTypes ? this.props.data.membershipTypes[0].slug : 'standard';
|
||||
|
||||
stripe.paymentRequestWithCardForm(options).then(
|
||||
(token) => {
|
||||
// returns a token.tokenId which should be saved
|
||||
this.props.requestMembershipCharge(
|
||||
this.props.userToken,
|
||||
{id: token.tokenId, email: this.props.user.email},
|
||||
membershipTypeSlug);
|
||||
},
|
||||
(error) => { /* FIXME: Happens only if card dialog is canceled? */ }
|
||||
);
|
||||
};
|
||||
|
||||
// fetchUser = () => {
|
||||
// this.props.fetchUser().then(() => {
|
||||
// this.setState({refreshing: false});
|
||||
// });
|
||||
// };
|
||||
|
||||
// _onRefresh() {
|
||||
// console.log('onRefresh')
|
||||
// this.setState({refreshing: true});
|
||||
// this.fetchUser()
|
||||
// }
|
||||
|
||||
// refreshControl() {
|
||||
// return (
|
||||
// <RefreshControl
|
||||
// refreshing={this.state.refreshing}
|
||||
// onRefresh={this._onRefresh.bind(this)}
|
||||
// />)
|
||||
// }
|
||||
}
|
||||
|
||||
const PROOF_QUERY = gql`{
|
||||
membershipTypes(isDefault: true) {
|
||||
slug
|
||||
price
|
||||
}
|
||||
}`;
|
||||
|
||||
const proofContainerWithState = connect(
|
||||
(store) => ({
|
||||
userToken: store.userToken,
|
||||
isChargingMembership: store.isChargingMembership,
|
||||
chargeError: store.chargeError
|
||||
}),
|
||||
{requestMembershipCharge}
|
||||
)(ProofContainer);
|
||||
|
||||
export default graphql(PROOF_QUERY)(proofContainerWithState);
|
||||
@@ -0,0 +1,259 @@
|
||||
import React, {Component} from 'react';
|
||||
import {Container, Header, Content, Form, Item, Input, Label, Spinner, Button, Text, Icon, Toast} from 'native-base';
|
||||
import {StyleSheet, View} from "react-native";
|
||||
import EmailValidator from 'email-validator';
|
||||
|
||||
import theme from "../../theme";
|
||||
|
||||
export default class UserRegister extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
email: '',
|
||||
phoneNumber: '',
|
||||
password: '',
|
||||
errors: {},
|
||||
touched: new Set()
|
||||
}
|
||||
};
|
||||
|
||||
validateForm(triggeredBy) {
|
||||
const fieldNames = ['firstName', 'lastName', 'email', 'phoneNumber', 'password'];
|
||||
|
||||
let errors = Object.assign({}, this.state.errors);
|
||||
let touched = new Set(this.state.touched).add(triggeredBy);
|
||||
|
||||
/* No empty fields */
|
||||
for(let key of fieldNames) {
|
||||
const value = this.state[key];
|
||||
if(value === '') {
|
||||
errors[key] = 'kan ikke være tomt';
|
||||
} else if(key === 'email' && !EmailValidator.validate(value)) {
|
||||
errors[key] = 'er ikke en gyldig e-post';
|
||||
} else {
|
||||
delete errors[key];
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({errors: errors, touched});
|
||||
};
|
||||
|
||||
fieldHasError(field) {
|
||||
return this.state.touched.has(field) && field in this.state.errors;
|
||||
}
|
||||
|
||||
canSubmitForm() {
|
||||
return Object.keys(this.state.errors).length === 0;
|
||||
}
|
||||
|
||||
firstNameInput() {
|
||||
return <Item error={this.fieldHasError('firstName')}>
|
||||
<Label>Fornavn</Label>
|
||||
<Input
|
||||
autoFocus={true}
|
||||
returnKeyType="next"
|
||||
onChangeText={(firstName) => {
|
||||
this.setState({firstName}, () => { this.validateForm('firstName'); });
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
this.refs.lastNameInput._root.focus()
|
||||
}}
|
||||
value={this.state.firstName}
|
||||
/>
|
||||
{this.fieldHasError('firstName') && <Icon name='close-circle' />}
|
||||
</Item>;
|
||||
}
|
||||
|
||||
lastNameInput() {
|
||||
return <Item error={this.fieldHasError('lastName')}>
|
||||
<Label>Etternavn</Label>
|
||||
<Input
|
||||
ref="lastNameInput"
|
||||
returnKeyType="next"
|
||||
onChangeText={(lastName) => {
|
||||
this.setState({lastName}, () => { this.validateForm('lastName'); });
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
this.refs.emailInput._root.focus()
|
||||
}}
|
||||
value={this.state.lastName}
|
||||
/>
|
||||
{this.fieldHasError('lastName') && <Icon name='close-circle' />}
|
||||
</Item>;
|
||||
}
|
||||
|
||||
emailInput() {
|
||||
return <Item error={this.fieldHasError('email')}>
|
||||
<Label>E-post</Label>
|
||||
<Input
|
||||
ref="emailInput"
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
returnKeyType="next"
|
||||
onChangeText={(email) => {
|
||||
this.setState({email}, () => { this.validateForm('email'); });
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
this.refs.phoneInput._root.focus()
|
||||
}}
|
||||
value={this.state.email}
|
||||
/>
|
||||
{this.fieldHasError('email') && <Icon name='close-circle' />}
|
||||
</Item>;
|
||||
}
|
||||
|
||||
phoneNumberInput() {
|
||||
return <Item error={this.fieldHasError('phoneNumber')}>
|
||||
<Label>Mobilnummer</Label>
|
||||
<Input
|
||||
ref="phoneInput"
|
||||
returnKeyType="next"
|
||||
keyboardType="phone-pad"
|
||||
onChangeText={(phoneNumber) => {
|
||||
this.setState({phoneNumber}, () => { this.validateForm('phoneNumber'); });
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
this.refs.passwordInput._root.focus()
|
||||
}}
|
||||
value={this.state.phoneNumber}
|
||||
/>
|
||||
{this.fieldHasError('phoneNumber') && <Icon name='close-circle' />}
|
||||
</Item>;
|
||||
}
|
||||
|
||||
passwordInput() {
|
||||
return <Item error={this.fieldHasError('password')}>
|
||||
<Label>Passord</Label>
|
||||
<Input
|
||||
ref="passwordInput"
|
||||
secureTextEntry={true}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
onChangeText={(password) => {
|
||||
this.setState({password}, () => { this.validateForm('password'); });
|
||||
}}
|
||||
onSubmitEditing={this.onRegisterPress}
|
||||
value={this.state.password}
|
||||
/>
|
||||
{this.fieldHasError('password') && <Icon name='close-circle' />}
|
||||
</Item>
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if(this.props.registerError !== nextProps.registerError) {
|
||||
this.setState({'errors': nextProps.registerError})
|
||||
}
|
||||
}
|
||||
|
||||
showNonFieldError = () => {
|
||||
const errors = this.props.registerError;
|
||||
if (Object.keys(errors).length !== 0 && 'non_field_errors' in errors) {
|
||||
const err = errors.non_field_errors;
|
||||
let errorFormatted = err ? err[0] : 'Kunne ikke registrere bruker, prøv igjen...';
|
||||
return <View style={styles.errorBox}><Text style={styles.errorMessage}>{errorFormatted}</Text></View>
|
||||
}
|
||||
|
||||
return <View style={styles.errorBox}/>
|
||||
};
|
||||
|
||||
showFieldError = (field) => {
|
||||
if(!this.fieldHasError(field) ) {
|
||||
return;
|
||||
}
|
||||
return <Item style={styles.errorText}><Text style={styles.errorMessage}>{this.state.errors[field]}</Text></Item>;
|
||||
};
|
||||
|
||||
showSpinner = () => {
|
||||
if (this.props.isRegisteringUser) {
|
||||
return <Spinner color="#f58220"/>
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Container style={styles.container}>
|
||||
<Content keyboardShouldPersistTaps='always'>
|
||||
<Form style={styles.card}>
|
||||
{this.firstNameInput()}
|
||||
{this.showFieldError('firstName')}
|
||||
{this.lastNameInput()}
|
||||
{this.showFieldError('lastName')}
|
||||
{this.emailInput()}
|
||||
{this.showFieldError('email')}
|
||||
{this.phoneNumberInput()}
|
||||
{this.showFieldError('phoneNumber')}
|
||||
{this.passwordInput()}
|
||||
{this.showFieldError('password')}
|
||||
{this.showNonFieldError()}
|
||||
{this.registerbutton()}
|
||||
{this.showSpinner()}
|
||||
</Form>
|
||||
</Content>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
onRegisterPress = () => {
|
||||
if( !this.canSubmitForm() ) {
|
||||
Toast.show({
|
||||
text: 'Noen av feltene er ikke fylt ut riktig',
|
||||
position: 'bottom',
|
||||
buttonText: 'OK',
|
||||
duration: 1500,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onRegisterPress(
|
||||
this.state.firstName,
|
||||
this.state.lastName,
|
||||
this.state.email,
|
||||
this.state.phoneNumber,
|
||||
this.state.password,
|
||||
);
|
||||
};
|
||||
|
||||
registerbutton() {
|
||||
const isDisabled = this.state.touched.size === 0 || this.props.isRegisteringUser || !this.canSubmitForm();
|
||||
|
||||
return (<Button
|
||||
full
|
||||
disabled={isDisabled}
|
||||
onPress={this.onRegisterPress}
|
||||
style={styles.registerButton}
|
||||
>
|
||||
<Text>Registrer meg</Text>
|
||||
</Button>);
|
||||
}
|
||||
}
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
input: {
|
||||
width: 320,
|
||||
fontSize: 20,
|
||||
height: 52,
|
||||
},
|
||||
registerButton: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
errorBox: {
|
||||
marginVertical: 10,
|
||||
},
|
||||
errorMessage: {
|
||||
textAlign: 'center',
|
||||
color: theme.colors.danger,
|
||||
fontSize: 14,
|
||||
},
|
||||
card: theme.card,
|
||||
errorText: {
|
||||
paddingTop: 2,
|
||||
paddingBottom: 12,
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from "react-redux";
|
||||
import UserRegister from "./UserRegister";
|
||||
import {requestRegisterUser} from "../../api";
|
||||
|
||||
class UserRegisterContainer extends Component {
|
||||
|
||||
constructor(state) {
|
||||
super(state);
|
||||
this.state = {
|
||||
isAuthenticated: false,
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.state.isAuthenticated !== nextProps.isAuthenticated) {
|
||||
if (nextProps.isAuthenticated) {
|
||||
this.props.onRegister();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onRegisterPress = (firstName, lastName, email, phoneNumber, password) => {
|
||||
this.props.requestRegisterUser(firstName, lastName, email, phoneNumber, password);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <UserRegister
|
||||
{...this.state}
|
||||
onRegisterPress={this.onRegisterPress}
|
||||
registerError={this.props.registerError}
|
||||
isRegisteringUser={this.props.isRegisteringUser}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
function storeToProps(store) {
|
||||
const errors = store.registerError === null ? {} : store.registerError;
|
||||
return {
|
||||
isAuthenticated: store.isAuthenticated,
|
||||
isRegisteringUser: store.isRegisteringUser,
|
||||
registerError: errors
|
||||
};
|
||||
}
|
||||
export default connect(
|
||||
storeToProps,
|
||||
{requestRegisterUser}
|
||||
)(UserRegisterContainer);
|
||||
@@ -0,0 +1,56 @@
|
||||
import {Platform, StyleSheet} from 'react-native';
|
||||
import {TabNavigator, StackNavigator} from "react-navigation";
|
||||
|
||||
import AboutScreen from "./screens/AboutScreen";
|
||||
import EventDetailScreen from "./screens/EventDetailScreen";
|
||||
import EventListScreen from "./screens/EventListScreen";
|
||||
import LoginScreen from "./screens/LoginScreen";
|
||||
import MembershipScreen from "./screens/MembershipScreen";
|
||||
import UserRegisterScreen from "./screens/UserRegisterScreen";
|
||||
|
||||
const tabBarRoutes = {
|
||||
EventList: { screen: EventListScreen },
|
||||
Membership: { screen: MembershipScreen },
|
||||
About: { screen: AboutScreen },
|
||||
};
|
||||
|
||||
const tabBarOptions = {
|
||||
tabBarPosition: 'bottom',
|
||||
tabBarOptions: {
|
||||
style: {
|
||||
...Platform.select({
|
||||
android: {
|
||||
backgroundColor: "#fff",
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: 'rgba(0, 0, 0, 0.1)'
|
||||
}
|
||||
})
|
||||
},
|
||||
indicatorStyle: {
|
||||
backgroundColor: "#f58220"
|
||||
},
|
||||
activeTintColor: '#f58220',
|
||||
inactiveTintColor: '#333333',
|
||||
showIcon: true,
|
||||
labelStyle: {
|
||||
fontSize: 10,
|
||||
marginBottom: 0,
|
||||
...Platform.select({
|
||||
android: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
}),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const tabNav = TabNavigator(tabBarRoutes, tabBarOptions);
|
||||
|
||||
const DuskenNavigation = StackNavigator({
|
||||
Root: { screen: tabNav },
|
||||
Login: { screen: LoginScreen },
|
||||
UserRegister: { screen: UserRegisterScreen },
|
||||
EventDetail: { screen: EventDetailScreen },
|
||||
});
|
||||
|
||||
export default DuskenNavigation;
|
||||
+70
-2
@@ -6,20 +6,42 @@ import {
|
||||
USER_DATA_REQUEST,
|
||||
USER_DATA_SUCCESS,
|
||||
USER_DATA_FAILURE,
|
||||
REGISTER_USER_REQUEST,
|
||||
REGISTER_USER_FAILURE,
|
||||
REGISTER_USER_SUCCESS, MEMBERSHIP_CHARGE_REQUEST, MEMBERSHIP_CHARGE_FAILURE, MEMBERSHIP_CHARGE_SUCCESS,
|
||||
} from './actions';
|
||||
|
||||
import { snakeToCamelCase } from './utils'
|
||||
|
||||
const initialState = {
|
||||
isAuthenticated: false,
|
||||
isLoggingIn: false,
|
||||
isFetchingUserData: false,
|
||||
isRegisteringUser: false,
|
||||
isChargingMembership: false,
|
||||
userToken: null,
|
||||
user: null,
|
||||
loginError: null,
|
||||
userError: null,
|
||||
registerError: null,
|
||||
chargeError: null,
|
||||
lastOrder: null,
|
||||
};
|
||||
|
||||
|
||||
function formatErrors(errs) {
|
||||
let _errs = {};
|
||||
for(let [key, value] of Object.entries(errs)) {
|
||||
_errs[snakeToCamelCase(key)] = value.join('\n');
|
||||
}
|
||||
return _errs
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default function duskenApp(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
/* Login */
|
||||
case LOGIN_REQUEST:
|
||||
return Object.assign({}, state, {
|
||||
isLoggingIn: true,
|
||||
@@ -42,9 +64,11 @@ export default function duskenApp(state = initialState, action) {
|
||||
case LOGOUT:
|
||||
return initialState;
|
||||
|
||||
/* User data */
|
||||
case USER_DATA_REQUEST:
|
||||
return Object.assign({}, state, {
|
||||
isFetchingUserData: true
|
||||
isFetchingUserData: true,
|
||||
userError: null
|
||||
});
|
||||
|
||||
case USER_DATA_FAILURE:
|
||||
@@ -56,7 +80,51 @@ export default function duskenApp(state = initialState, action) {
|
||||
case USER_DATA_SUCCESS:
|
||||
return Object.assign({}, state, {
|
||||
isFetchingUserData: false,
|
||||
user: action.data
|
||||
user: action.data,
|
||||
});
|
||||
|
||||
/* Register user */
|
||||
case REGISTER_USER_REQUEST:
|
||||
return Object.assign({}, state, {
|
||||
isRegisteringUser: true,
|
||||
registerError: null,
|
||||
});
|
||||
|
||||
case REGISTER_USER_FAILURE:
|
||||
return Object.assign({}, state, {
|
||||
isRegisteringUser: false,
|
||||
registerError: formatErrors(action.registerError)
|
||||
});
|
||||
|
||||
case REGISTER_USER_SUCCESS:
|
||||
let userData = action.data;
|
||||
const token = action.data.auth_token;
|
||||
delete userData['auth_token'];
|
||||
|
||||
return Object.assign({}, state, {
|
||||
isRegisteringUser: false,
|
||||
isAuthenticated: true,
|
||||
user: userData,
|
||||
userToken: token,
|
||||
});
|
||||
|
||||
/* User data */
|
||||
case MEMBERSHIP_CHARGE_REQUEST:
|
||||
return Object.assign({}, state, {
|
||||
isChargingMembership: true,
|
||||
chargeError: null
|
||||
});
|
||||
|
||||
case MEMBERSHIP_CHARGE_FAILURE:
|
||||
return Object.assign({}, state, {
|
||||
isChargingMembership: false,
|
||||
chargeError: action.chargeError
|
||||
});
|
||||
|
||||
case MEMBERSHIP_CHARGE_SUCCESS:
|
||||
return Object.assign({}, state, {
|
||||
isChargingMembership: false,
|
||||
lastOrder: action.data,
|
||||
});
|
||||
|
||||
default:
|
||||
|
||||
@@ -22,7 +22,8 @@ export default class LoginScreen extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<StyleProvider style={getTheme()}><LoginContainer onLogin={this.onLogin} />
|
||||
<StyleProvider style={getTheme()}>
|
||||
<LoginContainer onLogin={this.onLogin} />
|
||||
</StyleProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class MembershipScreen extends Component {
|
||||
),
|
||||
};
|
||||
|
||||
onLoginPress = () => {
|
||||
loginNavigate = () => {
|
||||
this.props.navigation.navigate('Login');
|
||||
};
|
||||
|
||||
@@ -27,10 +27,17 @@ export default class MembershipScreen extends Component {
|
||||
this.props.navigation.navigate('Membership');
|
||||
};
|
||||
|
||||
registerNavigate = () => {
|
||||
this.props.navigation.navigate('UserRegister');
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<StyleProvider style={getTheme()}>
|
||||
<MembershipContainer onLoginPress={this.onLoginPress} logoutNavigate={this.logoutNavigate} />
|
||||
<MembershipContainer
|
||||
onLoginPress={this.loginNavigate}
|
||||
onLogoutPress={this.logoutNavigate}
|
||||
onRegisterPress={this.registerNavigate} />
|
||||
</StyleProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import React, { Component } from 'react';
|
||||
import UserRegisterContainer from "../modules/register/UserRegisterContainer";
|
||||
import {StyleProvider} from "native-base";
|
||||
import getTheme from '../../native-base-theme/components';
|
||||
|
||||
export default class UserRegisterScreen extends Component {
|
||||
static navigationOptions = {
|
||||
title: 'Bli medlem',
|
||||
headerStyle: {
|
||||
backgroundColor: '#f58220',
|
||||
},
|
||||
headerTitleStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
headerTintColor: 'white',
|
||||
};
|
||||
|
||||
onRegister = () => {
|
||||
// This works since UserRegisterScreen is allways navigated to from MembershipScreen
|
||||
this.props.navigation.goBack();
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<StyleProvider style={getTheme()}>
|
||||
<UserRegisterContainer onRegister={this.onRegister} />
|
||||
</StyleProvider>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Platform } from "react-native";
|
||||
import platform from "native-base/src/theme/variables/platform";
|
||||
|
||||
const colors = {
|
||||
danger: platform.btnDangerBg
|
||||
};
|
||||
|
||||
const card = {
|
||||
...Platform.select({
|
||||
ios: {
|
||||
shadowColor: 'rgba(0,0,0, .2)',
|
||||
shadowOffset: {height: 0, width: 0},
|
||||
shadowOpacity: 1,
|
||||
shadowRadius: 1,
|
||||
},
|
||||
android: {
|
||||
elevation: 1,
|
||||
},
|
||||
}),
|
||||
padding: 8,
|
||||
margin: 8,
|
||||
backgroundColor: '#fff',
|
||||
};
|
||||
export default {card, colors};
|
||||
@@ -0,0 +1,3 @@
|
||||
export function snakeToCamelCase(val) {
|
||||
return val.replace(/_([a-z])/g, function (g) { return g[1].toUpperCase(); });
|
||||
}
|
||||
Reference in new issue
Block a user