diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..8c3380c
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,31 @@
+{
+ "extends": [
+ "airbnb-base",
+ "plugin:prettier/recommended",
+ "plugin:react/recommended",
+ "plugin:import/errors",
+ "plugin:import/warnings",
+ ],
+ "rules": {
+ "no-plusplus": 0,
+ "no-console": 0,
+ "no-underscore-dangle": 0,
+ "no-param-reassign": 0,
+ "react/prefer-stateless-function": 1,
+ "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
+ "react/sort-comp": 0,
+ "max-len": 0,
+ "no-use-before-define": ["error", { "functions": true, "classes": true, "variables": false }] // disable the rule for variables, but enable it for functions and classes
+
+ },
+ "plugins": [
+ "react",
+ "prettier"
+ ],
+ "parser": "babel-eslint",
+ "settings": {
+ "react": {
+ "version": "16.8"
+ }
+ }
+}
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..85a8c01
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,6 @@
+{
+ "singleQuote": true,
+ "trailingComma": "es5",
+ "printWidth": 120,
+ "arrowParens": "always"
+}
diff --git a/android/app/build.gradle b/android/app/build.gradle
index e8964bc..f41abc4 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -119,10 +119,13 @@ android {
}
signingConfigs {
release {
- storeFile file(DUSKEN_RELEASE_STORE_FILE)
- storePassword DUSKEN_RELEASE_STORE_PASSWORD
- keyAlias DUSKEN_RELEASE_KEY_ALIAS
- keyPassword DUSKEN_RELEASE_KEY_PASSWORD
+ // These variables are in ~/.gradle/gradle.properties
+ if (project.hasProperty('DUSKEN_RELEASE_STORE_FILE')) {
+ storeFile file(DUSKEN_RELEASE_STORE_FILE)
+ storePassword DUSKEN_RELEASE_STORE_PASSWORD
+ keyAlias DUSKEN_RELEASE_KEY_ALIAS
+ keyPassword DUSKEN_RELEASE_KEY_PASSWORD
+ }
}
}
buildTypes {
diff --git a/package.json b/package.json
index ea4c696..d881b15 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,9 @@
"android": "react-native run-android",
"build:android": "cd android && ./gradlew assembleRelease",
"emulator": "emulator -avd $(emulator -list-avds | head)&",
+ "format": "eslint --fix \"src/**/*.js\"",
"ios": "react-native run-ios",
+ "lint:format": "eslint --quiet \"src/**/*.js\"",
"release:android": "cd android && bundle exec fastlane beta",
"release:ios": "cd ios && bundle exec fastlane beta",
"start": "node node_modules/react-native/local-cli/cli.js start",
@@ -44,10 +46,19 @@
"devDependencies": {
"@babel/core": "^7.4.4",
"@babel/runtime": "^7.4.4",
+ "babel-eslint": "^10.0.1",
"babel-jest": "^24.7.1",
+ "eslint": "^5.16.0",
+ "eslint-config-airbnb": "^17.1.0",
+ "eslint-config-prettier": "^4.0.0",
+ "eslint-plugin-import": "^2.16.0",
+ "eslint-plugin-jsx-a11y": "^6.2.1",
+ "eslint-plugin-prettier": "^3.0.1",
+ "eslint-plugin-react": "^7.12.4",
"jest": "^24.7.1",
"jest-fetch-mock": "^1.6.5",
"metro-react-native-babel-preset": "^0.54.0",
+ "prettier": "^1.17.0",
"react-dom": "16.8.3",
"react-test-renderer": "16.8.3"
}
diff --git a/src/App.js b/src/App.js
index 81def68..4e3b4e3 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,31 +1,30 @@
-import React, {Component} from 'react';
-import {Provider} from 'react-redux';
-import {PersistGate} from 'redux-persist/es/integration/react'
+import React, { Component } from 'react';
+import { Provider } from 'react-redux';
+import { PersistGate } from 'redux-persist/es/integration/react';
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 {store, persistor} from './reduxStore';
+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 { store, persistor } from './reduxStore';
const apolloClient = new ApolloClient({
- link: new HttpLink({uri: `${Config.DUSKEN_API_URL}/api/graphql/`}),
- cache: new InMemoryCache()
+ link: new HttpLink({ uri: `${Config.DUSKEN_API_URL}/api/graphql/` }),
+ cache: new InMemoryCache(),
});
export default class App extends Component {
- render() {
- return (
-
-
-
-
-
-
-
- )
- }
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
}
diff --git a/src/Dusken.js b/src/Dusken.js
index c88f052..7744392 100644
--- a/src/Dusken.js
+++ b/src/Dusken.js
@@ -1,15 +1,16 @@
-import React, {Component} from 'react';
-import {connect} from "react-redux";
-import {Root} from 'native-base';
-import DuskenNavigation from "./navigation";
-
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { Root } from 'native-base';
+import DuskenNavigation from './navigation';
class DuskenContainer extends Component {
- render() {
- return (
-
- )
- }
+ render() {
+ return (
+
+
+
+ );
+ }
}
-export default connect()(DuskenContainer);
\ No newline at end of file
+export default connect()(DuskenContainer);
diff --git a/src/actions.js b/src/actions.js
index 55f4c85..a344129 100644
--- a/src/actions.js
+++ b/src/actions.js
@@ -13,103 +13,116 @@ const MEMBERSHIP_CHARGE_SUCCESS = 'MEMBERSHIP_CHARGE_SUCCESS';
const MEMBERSHIP_CHARGE_FAILURE = 'MEMBERSHIP_CHARGE_FAILURE';
function loginRequest() {
- return {
- type: LOGIN_REQUEST
- }
+ return {
+ type: LOGIN_REQUEST,
+ };
}
function loginSuccess(username, token) {
- return {
- type: LOGIN_SUCCESS,
- username,
- token
- }
+ return {
+ type: LOGIN_SUCCESS,
+ username,
+ token,
+ };
}
function loginFailure(loginError) {
- return {
- type: LOGIN_FAILURE,
- loginError
- }
+ return {
+ type: LOGIN_FAILURE,
+ loginError,
+ };
}
function logout() {
- return {
- type: LOGOUT
- }
+ return {
+ type: LOGOUT,
+ };
}
function userDataRequest() {
- return {
- type: USER_DATA_REQUEST
- }
+ return {
+ type: USER_DATA_REQUEST,
+ };
}
function userDataSuccess(data) {
- return {
- type: USER_DATA_SUCCESS,
- data
- }
+ return {
+ type: USER_DATA_SUCCESS,
+ data,
+ };
}
function userDataFailure(userError) {
- return {
- type: USER_DATA_FAILURE,
- userError
- }
+ return {
+ type: USER_DATA_FAILURE,
+ userError,
+ };
}
function registerUserRequest() {
- return {
- type: REGISTER_USER_REQUEST
- }
+ return {
+ type: REGISTER_USER_REQUEST,
+ };
}
function registerUserSuccess(data) {
- return {
- type: REGISTER_USER_SUCCESS,
- data
- }
+ return {
+ type: REGISTER_USER_SUCCESS,
+ data,
+ };
}
function registerUserFailure(registerError) {
- return {
- type: REGISTER_USER_FAILURE,
- registerError
- }
+ return {
+ type: REGISTER_USER_FAILURE,
+ registerError,
+ };
}
function membershipChargeRequest() {
- return {
- type: MEMBERSHIP_CHARGE_REQUEST
- }
+ return {
+ type: MEMBERSHIP_CHARGE_REQUEST,
+ };
}
function membershipChargeSuccess(data) {
- return {
- type: MEMBERSHIP_CHARGE_SUCCESS,
- data
- }
+ return {
+ type: MEMBERSHIP_CHARGE_SUCCESS,
+ data,
+ };
}
function membershipChargeFailure(chargeError) {
- return {
- type: MEMBERSHIP_CHARGE_FAILURE,
- chargeError
- }
+ return {
+ type: MEMBERSHIP_CHARGE_FAILURE,
+ chargeError,
+ };
}
export {
- LOGIN_REQUEST, loginRequest,
- LOGIN_SUCCESS, loginSuccess,
- LOGIN_FAILURE, loginFailure,
- LOGOUT, logout,
- USER_DATA_REQUEST, userDataRequest,
- USER_DATA_SUCCESS, userDataSuccess,
- USER_DATA_FAILURE, userDataFailure,
- REGISTER_USER_REQUEST, registerUserRequest,
- REGISTER_USER_SUCCESS, registerUserSuccess,
- REGISTER_USER_FAILURE, registerUserFailure,
- MEMBERSHIP_CHARGE_REQUEST, membershipChargeRequest,
- MEMBERSHIP_CHARGE_SUCCESS, membershipChargeSuccess,
- MEMBERSHIP_CHARGE_FAILURE, membershipChargeFailure,
-};
\ No newline at end of file
+ LOGIN_REQUEST,
+ loginRequest,
+ LOGIN_SUCCESS,
+ loginSuccess,
+ LOGIN_FAILURE,
+ loginFailure,
+ LOGOUT,
+ logout,
+ USER_DATA_REQUEST,
+ userDataRequest,
+ USER_DATA_SUCCESS,
+ userDataSuccess,
+ USER_DATA_FAILURE,
+ userDataFailure,
+ REGISTER_USER_REQUEST,
+ registerUserRequest,
+ REGISTER_USER_SUCCESS,
+ registerUserSuccess,
+ REGISTER_USER_FAILURE,
+ registerUserFailure,
+ MEMBERSHIP_CHARGE_REQUEST,
+ membershipChargeRequest,
+ MEMBERSHIP_CHARGE_SUCCESS,
+ membershipChargeSuccess,
+ MEMBERSHIP_CHARGE_FAILURE,
+ membershipChargeFailure,
+};
diff --git a/src/api.js b/src/api.js
index 3c13963..dd96f18 100644
--- a/src/api.js
+++ b/src/api.js
@@ -1,148 +1,154 @@
import Config from 'react-native-config';
import {
- loginFailure, loginRequest, loginSuccess,
- registerUserFailure, registerUserRequest, registerUserSuccess,
- userDataFailure, userDataRequest, userDataSuccess,
- membershipChargeFailure, membershipChargeRequest, membershipChargeSuccess,
-} from "./actions";
-import { fetchWithTimeout } from "./utils";
+ loginFailure,
+ loginRequest,
+ loginSuccess,
+ registerUserFailure,
+ registerUserRequest,
+ registerUserSuccess,
+ userDataFailure,
+ userDataRequest,
+ userDataSuccess,
+ membershipChargeFailure,
+ membershipChargeRequest,
+ membershipChargeSuccess,
+} from './actions';
+import { fetchWithTimeout } from './utils';
export function requestLogin(username, password) {
- return (dispatch) => {
- // We are now logging in
- dispatch(loginRequest());
+ return (dispatch) => {
+ // We are now logging in
+ dispatch(loginRequest());
- return fetchWithTimeout(`${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']}))
- }
- )
- }
+ return fetchWithTimeout(`${Config.DUSKEN_API_URL}/auth/obtain-token/`, {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ username,
+ 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 (dispatch) => {
+ // We are now fetching user data
+ dispatch(userDataRequest());
- return fetchWithTimeout(`${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']}))
- }
- )
- }
+ return fetchWithTimeout(`${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 (dispatch) => {
+ dispatch(registerUserRequest());
- return fetchWithTimeout(`${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']}))
- }
- )
- }
+ return fetchWithTimeout(`${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,
+ phone_number: phoneNumber,
+ 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 (dispatch) => {
+ dispatch(membershipChargeRequest());
- return fetchWithTimeout(`${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['detail'] || 'Kunne ikke belaste bankkortet, prøv igjen'))
- }
- )
- }
+ return fetchWithTimeout(`${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,
+ 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.detail || 'Kunne ikke belaste bankkortet, prøv igjen'));
+ }
+ );
+ };
}
-
-
diff --git a/src/modules/about/About.js b/src/modules/about/About.js
index 8301c7d..3fcb7cd 100644
--- a/src/modules/about/About.js
+++ b/src/modules/about/About.js
@@ -1,156 +1,191 @@
import React, { Component } from 'react';
-import {Text, ScrollView, View, Platform, StyleSheet, Image, Linking, TouchableOpacity} from "react-native";
+import { Text, ScrollView, View, Platform, StyleSheet, Image, Linking, TouchableOpacity } from 'react-native';
// import HTMLView from 'react-native-htmlview';
-import {Button, Text as NBText, Icon} from 'native-base';
-import theme from "../../theme";
+import { Button, Text as NBText, Icon } from 'native-base';
+import theme from '../../theme';
const CHATEAU_NEUF_ADDRESS = 'Det Norske Studentersamfund, Slemdalsveien 15, 0369 Oslo';
export default class About extends Component {
- /* FIXME: Values here are pretty hardcoded. Should fetch config from a JSON-file or API */
+ /* FIXME: Values here are pretty hardcoded. Should fetch config from a JSON-file or API */
- openFacebook() {
- /* Ref: https://stackoverflow.com/questions/4810803/open-facebook-page-from-android-app */
- const url = Platform.select({
- ios: 'fb://page/?id=23664032291',
- android: 'fb://page/23664032291/'
- });
- Linking.canOpenURL(url).then(supported => {
- if (!supported) {
- return Linking.openURL('https://www.facebook.com/studentersamfundet/');
- } else {
- return Linking.openURL(url);
- }
- }).catch(err => console.error('An error occurred', err));
- }
- openInstagram() {
- /* Ref: */
- const url = Platform.select({
- ios: 'instagram://user?username=studentersamfundet',
- android: 'http://instagram.com/_u/studentersamfundet'
- });
+ openFacebook() {
+ /* Ref: https://stackoverflow.com/questions/4810803/open-facebook-page-from-android-app */
+ const url = Platform.select({
+ ios: 'fb://page/?id=23664032291',
+ android: 'fb://page/23664032291/',
+ });
+ Linking.canOpenURL(url)
+ .then((supported) => {
+ if (!supported) {
+ return Linking.openURL('https://www.facebook.com/studentersamfundet/');
+ }
+ return Linking.openURL(url);
+ })
+ .catch((err) => console.error('An error occurred', err));
+ }
- Linking.canOpenURL(url).then(supported => {
- if (!supported) {
- return Linking.openURL('https://www.instagram.com/studentersamfundet/');
- } else {
- return Linking.openURL(url);
- }
- }).catch(err => console.error('An error occurred', err));
- }
+ openInstagram() {
+ /* Ref: */
+ const url = Platform.select({
+ ios: 'instagram://user?username=studentersamfundet',
+ android: 'http://instagram.com/_u/studentersamfundet',
+ });
- openMap() {
- const url = Platform.select({
- ios: `comgooglemaps://?q=${CHATEAU_NEUF_ADDRESS}`,
- android: `https://www.google.com/maps/search/?api=1&query=${CHATEAU_NEUF_ADDRESS}`
- });
- Linking.canOpenURL(url).then(supported => {
- if (!supported) {
- return Linking.openURL(`https://www.google.com/maps/search/?api=1&query=${CHATEAU_NEUF_ADDRESS}`);
- } else {
- return Linking.openURL(url);
- }
- }).catch(err => console.error('An error occurred', err));
- }
+ Linking.canOpenURL(url)
+ .then((supported) => {
+ if (!supported) {
+ return Linking.openURL('https://www.instagram.com/studentersamfundet/');
+ }
+ return Linking.openURL(url);
+ })
+ .catch((err) => console.error('An error occurred', err));
+ }
- render() {
- return (
-
-
- Det Norske Studentersamfund
- Linking.openURL('https://www.studentersamfundet.no/')}>
-
-
- Følg oss på
-
-
- Facebook
-
-
- Instagram
-
-
+ openMap() {
+ const url = Platform.select({
+ ios: `comgooglemaps://?q=${CHATEAU_NEUF_ADDRESS}`,
+ android: `https://www.google.com/maps/search/?api=1&query=${CHATEAU_NEUF_ADDRESS}`,
+ });
+ Linking.canOpenURL(url)
+ .then((supported) => {
+ if (!supported) {
+ return Linking.openURL(`https://www.google.com/maps/search/?api=1&query=${CHATEAU_NEUF_ADDRESS}`);
+ }
+ return Linking.openURL(url);
+ })
+ .catch((err) => console.error('An error occurred', err));
+ }
- Adresse
- Det Norske Studentersamfund{"\n"}Slemdalsveien 15, 0369 Oslo
-
-
-
- Åpningstider
-
-
-
- Ta kontakt
-
-
-
-
-
-
-
-
+ render() {
+ return (
+
+
+ Det Norske Studentersamfund
+ Linking.openURL('https://www.studentersamfundet.no/')}>
+
+
+ Følg oss på
+
+
+
+ Facebook
+
+
+
+ Instagram
+
+
- Chateau Neuf
-
- Studentene i Oslo har sitt naturlige tilholdssted på Det Norske Studentersamfund, i hyggelige lokaler på Chateau Neuf øverst på Majorstuen. Her er det åpent alle dager unntatt søndag, og hver dag skjer det en rekke ting i våre mange arrangementslokaler. Enten man ønsker en tur i baren, på kafé, på debatt, på konsert, teater eller kino, har man muligheten på Chateau Neuf.
- Chateau Neuf er et frivillig drevet studenthus. Studenter over alt i Oslo kan komme hit og få nyttig og spennende erfaring med å drive et av Oslos største kulturhus. Her kan du stå i bar, sette lys og lyd, jobbe med markedsføring, produsere konserter, bli kjent med hundrevis av bra mennesker og få minner for livet.
- Alle studentforeninger i Oslo kan arrangere gratis på Chateau Neuf. Skal du arrangere en fest, sette en konsert, holde et foredrag eller gjennomføre et møte, har vi lokaler som kan brukes til dette.
+ Adresse
+
+ Det Norske Studentersamfund{'\n'}Slemdalsveien 15, 0369 Oslo
+
+
+
+
+ Åpningstider
+
+
+
+ Ta kontakt
+
+
+
+
+
+
+
+
- {/**/}
-
-
- )
- }
+ Chateau Neuf
+
+
+ Studentene i Oslo har sitt naturlige tilholdssted på Det Norske Studentersamfund, i hyggelige lokaler på
+ Chateau Neuf øverst på Majorstuen. Her er det åpent alle dager unntatt søndag, og hver dag skjer det en
+ rekke ting i våre mange arrangementslokaler. Enten man ønsker en tur i baren, på kafé, på debatt, på
+ konsert, teater eller kino, har man muligheten på Chateau Neuf.
+
+
+ Chateau Neuf er et frivillig drevet studenthus. Studenter over alt i Oslo kan komme hit og få nyttig og
+ spennende erfaring med å drive et av Oslos største kulturhus. Her kan du stå i bar, sette lys og lyd, jobbe
+ med markedsføring, produsere konserter, bli kjent med hundrevis av bra mennesker og få minner for livet.
+
+
+ Alle studentforeninger i Oslo kan arrangere gratis på Chateau Neuf. Skal du arrangere en fest, sette en
+ konsert, holde et foredrag eller gjennomføre et møte, har vi lokaler som kan brukes til dette.
+
+
+ {/* */}
+
+
+ );
+ }
}
-
const styles = StyleSheet.create({
- header: {
- fontSize: 20,
- fontWeight: 'bold',
- color: '#000',
- textAlign: 'center',
- },
- paragraph: {
- fontSize: 16,
- color: '#000',
- paddingBottom: 10,
- lineHeight: 25,
- },
- card: theme.card,
- featuredImage: {
- height: 230,
- width: null,
- },
- logo: {
- height: 128,
- width: null,
- marginBottom: 10,
- },
- icon: {
- fontSize: 16,
- },
- largeIcon: {
- fontSize: 40,
- },
- section: {
- marginTop: 8,
- marginBottom: 20,
- alignSelf: 'center',
- },
- someBtn: {
- flex: 1,
- alignItems: 'center',
- }
+ header: {
+ fontSize: 20,
+ fontWeight: 'bold',
+ color: '#000',
+ textAlign: 'center',
+ },
+ paragraph: {
+ fontSize: 16,
+ color: '#000',
+ paddingBottom: 10,
+ lineHeight: 25,
+ },
+ card: theme.card,
+ featuredImage: {
+ height: 230,
+ width: null,
+ },
+ logo: {
+ height: 128,
+ width: null,
+ marginBottom: 10,
+ },
+ icon: {
+ fontSize: 16,
+ },
+ largeIcon: {
+ fontSize: 40,
+ },
+ section: {
+ marginTop: 8,
+ marginBottom: 20,
+ alignSelf: 'center',
+ },
+ someBtn: {
+ flex: 1,
+ alignItems: 'center',
+ },
});
// const HTMLStyles = StyleSheet.create({
@@ -165,4 +200,4 @@ const styles = StyleSheet.create({
// marginTop: -20,
// marginBottom: -30,
// },
-// });
\ No newline at end of file
+// });
diff --git a/src/modules/about/AboutContainer.js b/src/modules/about/AboutContainer.js
index 7f4aaa4..dd811ce 100644
--- a/src/modules/about/AboutContainer.js
+++ b/src/modules/about/AboutContainer.js
@@ -1,45 +1,12 @@
-import {connect} from "react-redux";
-import React, {Component} from 'react';
-import Config from 'react-native-config';
+import { connect } from 'react-redux';
+import React, { Component } from 'react';
-import About from "./About";
+import About from './About';
class AboutContainer extends Component {
- // constructor(props) {
- // super(props);
- // this.state = {
- // openingHours: '',
- // loading: false,
- // error: null,
- // };
- // }
- //
- // componentDidMount() {
- // this.fetchOpeningHours();
- // }
- //
- // fetchOpeningHours() {
- // const url = `${Config.EVENT_API_URL}/wp-json/wp/v2/pages/?slug=aapningstider`;
- // this.setState({ loading: true });
- //
- // fetch(url)
- // .then(res => res.json())
- // .then(res => {
- // this.setState({
- // openingHours: res ? res[0].content.rendered : '',
- // error: res.error || null,
- // loading: false,
- // });
- //
- // })
- // .catch(error => {
- // this.setState({ error, loading: false });
- // });
- // }
-
- render() {
- return ;
- }
+ render() {
+ return ;
+ }
}
-export default connect()(AboutContainer);
\ No newline at end of file
+export default connect()(AboutContainer);
diff --git a/src/modules/events/EventDetail.js b/src/modules/events/EventDetail.js
index c27cd21..9426020 100644
--- a/src/modules/events/EventDetail.js
+++ b/src/modules/events/EventDetail.js
@@ -1,305 +1,325 @@
import React, { Component } from 'react';
-import {Linking, StyleSheet, ScrollView, Text, Platform, View, Image, 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 {Icon} from "native-base";
-import theme from "../../theme";
+import moment from 'moment';
+import { Icon } from 'native-base';
+import theme from '../../theme';
moment.locale('nb');
const CHATEAU_NEUF_ADDRESS = 'Chateau Neuf, Slemdalsveien 15, 0369 Oslo';
export default class EventDetail extends Component {
+ _formatTime(time) {
+ return moment(time).format('HH:mm');
+ }
- _formatTime(time) {
- return moment(time).format('HH:mm');
+ _formatMonth(time) {
+ return moment(time).format('MMM');
+ }
+
+ _formatDay(time) {
+ return moment(time).format('DD.');
+ }
+
+ _formatLocalDay(time) {
+ return moment(time).format('ddd');
+ }
+
+ _formatYear(time) {
+ return moment(time).format('YYYY');
+ }
+
+ _formatRelative(time) {
+ return moment(time).fromNow();
+ }
+
+ _formatLocation() {
+ if (this.props.item.venue !== 'Annetsteds') {
+ return CHATEAU_NEUF_ADDRESS;
+ }
+ return 'Ukjent adresse';
+ }
+
+ _formatTicketText() {
+ /* FIXME: This should be handled by API */
+ const { item } = this.props;
+ let reg_kr = '';
+ let mem_kr = '';
+ if (item.price_regular === '0') {
+ item.price_regular = 'Gratis';
+ }
+ if (item.price_member === '0') {
+ item.price_member = 'Gratis';
+ }
+ if (item.price_regular !== 'Gratis') {
+ reg_kr = ' kr';
+ }
+ if (item.price_member !== 'Gratis') {
+ mem_kr = ' kr';
}
- _formatMonth(time) {
- return moment(time).format('MMM');
+ let text = '';
+ if (item.price_regular && item.price_member) {
+ text = `Pris: ${item.price_regular}${reg_kr} / Medlemmer: ${item.price_member}${mem_kr}`;
+ } else if (item.price_regular) {
+ text = `Pris: ${item.price_regular}${reg_kr}`;
+ } else if (item.price_member) {
+ text = `Pris (Medlemmer): ${item.price_member}${mem_kr}`;
+ } else {
+ return '';
}
+ return text;
+ }
- _formatDay(time) {
- return moment(time).format('DD.');
- }
- _formatLocalDay(time) {
- return moment(time).format('ddd')
- }
+ onTicketUrlPress(link) {
+ Linking.openURL(link);
+ }
- _formatYear(time) {
- return moment(time).format('YYYY');
+ onFacebookUrlPress(link) {
+ const fbEventPattern = /https?:\/\/www\.facebook\.com\/events\/(\d+)\/?/i;
+ const matches = fbEventPattern.exec(link);
+ let iosURL = link;
+ if (matches && matches.length) {
+ iosURL = `fb://event/?id=${matches[1]}`;
}
-
- _formatRelative(time) {
- return moment(time).fromNow();
- }
- _formatLocation() {
- if(this.props.item.venue !== 'Annetsteds') {
- return CHATEAU_NEUF_ADDRESS;
+ const url = Platform.select({
+ ios: iosURL,
+ android: link,
+ });
+ Linking.canOpenURL(url)
+ .then((supported) => {
+ if (!supported) {
+ return Linking.openURL(link);
}
- return 'Ukjent adresse'
+ return Linking.openURL(url);
+ })
+ .catch((err) => console.error('An error occurred', err));
+ }
+
+ onLocationPress(venue) {
+ if (venue !== 'Annetsteds') {
+ Linking.openURL(`https://www.google.com/maps/dir/?api=1&destination=${CHATEAU_NEUF_ADDRESS}`);
+ }
+ }
+
+ showPriceAndTicket() {
+ const { item } = this.props;
+ const text = this._formatTicketText();
+
+ if (text === '') {
+ return;
}
- _formatTicketText() {
- /* FIXME: This should be handled by API */
- const {item} = this.props;
- let reg_kr = '';
- let mem_kr = '';
- if (item.price_regular === '0') {
- item.price_regular = 'Gratis'
- }
- if (item.price_member === '0') {
- item.price_member = 'Gratis'
- }
- if (item.price_regular !== 'Gratis') {
- reg_kr = " kr"
- }
- if (item.price_member !== 'Gratis') {
- mem_kr = " kr"
- }
-
- let text = '';
- if (item.price_regular && item.price_member) {
- text = `Pris: ${item.price_regular}${reg_kr} / Medlemmer: ${item.price_member}${mem_kr}`;
- }
- else if (item.price_regular) {
- text = `Pris: ${item.price_regular}${reg_kr}`;
- }
- else if (item.price_member) {
- text = `Pris (Medlemmer): ${item.price_member}${mem_kr}`;
- } else {
- return '';
- }
- return text;
+ if (item.ticket_url) {
+ return (
+ this.onTicketUrlPress(item.ticket_url)}>
+
+
+
+
+ {text}
+ Kjøp billett
+
+
+ );
}
- onTicketUrlPress(link) {
- Linking.openURL(link);
+ return (
+
+
+
+
+
+ {text}
+ Billett i døra
+
+
+ );
+ }
+
+ showFacebutton() {
+ const { item } = this.props;
+ if (!item.facebook_url) {
+ return;
}
- onFacebookUrlPress(link) {
- const fbEventPattern = /https?:\/\/www\.facebook\.com\/events\/(\d+)\/?/i;
- const matches = fbEventPattern.exec(link);
- let iosURL = link;
- if( matches && matches.length ) {
- iosURL = 'fb://event/?id=' + matches[1];
- }
- const url = Platform.select({
- ios: iosURL,
- android: link
- });
- Linking.canOpenURL(url).then(supported => {
- if (!supported) {
- return Linking.openURL(link);
- } else {
- return Linking.openURL(url);
- }
- }).catch(err => console.error('An error occurred', err));
+ return (
+ this.onFacebookUrlPress(item.facebook_url)} style={styles.metaInner}>
+
+
+
+
+ På Facebook
+
+
+ );
+ }
+
+ showImage() {
+ const { item } = this.props;
+
+ if (item.thumbnail.medium_large) {
+ return ;
}
+ }
- onLocationPress(venue) {
- if( venue !== 'Annetsteds' ) {
- Linking.openURL(`https://www.google.com/maps/dir/?api=1&destination=${CHATEAU_NEUF_ADDRESS}`);
- }
+ showYear() {
+ const { item } = this.props;
+
+ if (moment().year() !== moment(item.start_time).year()) {
+ return {this._formatYear(item.start_time)};
}
+ }
- showPriceAndTicket() {
- const {item} = this.props;
- const text = this._formatTicketText();
+ render() {
+ const { item } = this.props;
- if(text === '') {
- return;
- }
-
- if(item.ticket_url) {
- return (
- this.onTicketUrlPress(item.ticket_url)}>
-
-
- {text}
- Kjøp billett
-
- );
- }
-
- return (
-
-
-
- {text}
- Billett i døra
-
- )
- }
-
- showFacebutton() {
- const {item} = this.props;
- if (!item.facebook_url) { return;}
-
- return (
- this.onFacebookUrlPress(item.facebook_url)} style={styles.metaInner}>
-
-
- På Facebook
-
-
- );
- }
-
- showImage() {
- const {item} = this.props;
-
- if (item.thumbnail.medium_large) {
- return ;
- }
- }
-
- showYear() {
- const {item} = this.props;
-
- if(moment().year() !== moment(item.start_time).year()) {
- return {this._formatYear(item.start_time)}
- }
- }
-
- render() {
- const {item} = this.props;
-
- return (
-
- {this.showImage()}
-
- {/* Date and title */}
-
-
-
- {this._formatDay(item.start_time)}
- {this._formatMonth(item.start_time)}
- {this.showYear()}
-
-
-
- {item.title.decoded}
-
-
- {/* Time and calendar */}
-
-
-
- {this._formatLocalDay(item.start_time)} kl. {this._formatTime(item.start_time)} - {this._formatTime(item.end_time)}
- {this._formatRelative(item.start_time)}
-
-
- {/* Location and maps */}
- this.onLocationPress(item.venue)}>
-
-
- {item.venue}
- {this._formatLocation()}
-
-
- {this.showPriceAndTicket()}
- {this.showFacebutton()}
-
-
-
- )
- }
+ return (
+
+ {this.showImage()}
+
+ {/* Date and title */}
+
+
+
+ {this._formatDay(item.start_time)}
+ {this._formatMonth(item.start_time)}
+ {this.showYear()}
+
+
+
+
+ {item.title.decoded}
+
+
+
+ {/* Time and calendar */}
+
+
+
+
+
+
+ {this._formatLocalDay(item.start_time)} kl. {this._formatTime(item.start_time)} -{' '}
+ {this._formatTime(item.end_time)}
+
+ {this._formatRelative(item.start_time)}
+
+
+ {/* Location and maps */}
+ this.onLocationPress(item.venue)}>
+
+
+
+
+ {item.venue}
+
+ {this._formatLocation()}
+
+
+
+ {this.showPriceAndTicket()}
+ {this.showFacebutton()}
+
+
+
+ );
+ }
}
const styles = StyleSheet.create({
- dateAndTitle: {
- flexDirection: 'row',
- marginBottom: 8
- },
- titleContainer: {
- paddingLeft: 10,
- justifyContent: 'center',
- flex: 4,
- },
- title: {
- fontSize: 20,
- fontWeight: 'bold',
- color: '#000',
- },
- card: theme.card,
- image: {
- height: 260,
- width: null
- },
- time: {
- fontSize: 14,
- color: '#666'
- },
- metaInner: {
- flexDirection: 'row',
- marginVertical: 8,
- },
- metaIcon: {
- width: 16,
- paddingTop: 3,
- marginHorizontal: 8,
- marginVertical: 8,
- },
- metaText: {
- color: '#000',
- },
- metaSubtitle: {
- color: '#666',
- },
- content: {
- borderTopWidth: StyleSheet.hairlineWidth,
- borderColor: '#ccc',
- marginTop: 8,
- paddingTop: 10,
- },
- dateContainer: {
- flex: 1,
- justifyContent: 'center',
- },
- dateCard: {
- margin: 0,
- padding: 0,
- paddingBottom: 6,
- width: 62,
- },
- day: {
- paddingTop: 5,
- fontSize: 20,
- color: '#000',
- textAlign: 'center',
- },
- month: {
- textAlign: 'center',
- paddingHorizontal: 16,
- },
- year: {
- fontSize: 9,
- color: '#fff',
- backgroundColor: '#f58220',
- textAlign: 'center',
- paddingRight: 20,
- paddingBottom: 3,
- paddingLeft: 20,
- paddingTop: 3,
- },
- icons: {
- fontSize: 16,
- },
-
+ dateAndTitle: {
+ flexDirection: 'row',
+ marginBottom: 8,
+ },
+ titleContainer: {
+ paddingLeft: 10,
+ justifyContent: 'center',
+ flex: 4,
+ },
+ title: {
+ fontSize: 20,
+ fontWeight: 'bold',
+ color: '#000',
+ },
+ card: theme.card,
+ image: {
+ height: 260,
+ width: null,
+ },
+ time: {
+ fontSize: 14,
+ color: '#666',
+ },
+ metaInner: {
+ flexDirection: 'row',
+ marginVertical: 8,
+ },
+ metaIcon: {
+ width: 16,
+ paddingTop: 3,
+ marginHorizontal: 8,
+ marginVertical: 8,
+ },
+ metaText: {
+ color: '#000',
+ },
+ metaSubtitle: {
+ color: '#666',
+ },
+ content: {
+ borderTopWidth: StyleSheet.hairlineWidth,
+ borderColor: '#ccc',
+ marginTop: 8,
+ paddingTop: 10,
+ },
+ dateContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ },
+ dateCard: {
+ margin: 0,
+ padding: 0,
+ paddingBottom: 6,
+ width: 62,
+ },
+ day: {
+ paddingTop: 5,
+ fontSize: 20,
+ color: '#000',
+ textAlign: 'center',
+ },
+ month: {
+ textAlign: 'center',
+ paddingHorizontal: 16,
+ },
+ year: {
+ fontSize: 9,
+ color: '#fff',
+ backgroundColor: '#f58220',
+ textAlign: 'center',
+ paddingRight: 20,
+ paddingBottom: 3,
+ paddingLeft: 20,
+ paddingTop: 3,
+ },
+ icons: {
+ fontSize: 16,
+ },
});
-//FIXME: Ninja margin
+// FIXME: Ninja margin
const HTMLStyles = StyleSheet.create({
- p: {
- fontSize: 16,
- marginBottom: -30,
- color: '#000',
- },
- ul: {
- fontSize: 16,
- color: '#000',
- marginTop: -20,
- marginBottom: -30,
- },
-});
\ No newline at end of file
+ p: {
+ fontSize: 16,
+ marginBottom: -30,
+ color: '#000',
+ },
+ ul: {
+ fontSize: 16,
+ color: '#000',
+ marginTop: -20,
+ marginBottom: -30,
+ },
+});
diff --git a/src/modules/events/EventList.js b/src/modules/events/EventList.js
index 3b7921c..57cd24c 100644
--- a/src/modules/events/EventList.js
+++ b/src/modules/events/EventList.js
@@ -1,122 +1,144 @@
-import {StyleSheet, View, Platform} from "react-native";
-import {SectionList} from 'react-navigation';
-import {Card, ListItem, CardItem, Body, Text as Text, Left, Right, Icon, Button, Content, Spinner} from 'native-base';
+import { StyleSheet, View, Platform } from 'react-native';
+import { SectionList } from 'react-navigation';
+import { Card, ListItem, CardItem, Body, Text, Left, Right, Icon, Button, Content, Spinner } from 'native-base';
import React, { Component } from 'react';
-import moment from "moment";
+import moment from 'moment';
import 'moment/locale/nb';
-import theme from "../../theme";
+import theme from '../../theme';
moment.locale('nb');
export default class EventList extends Component {
- _renderItem = ({item}) => (
- { this._onPressItem(item); }} style={styles.listItem}>
-
- {item.title.decoded}
- {this._formatTime(item.start_time)}
-
-
-
-
-
+ _renderItem = ({ item }) => (
+ {
+ this._onPressItem(item);
+ }}
+ style={styles.listItem}
+ >
+
+
+ {item.title.decoded}
+
+ {this._formatTime(item.start_time)}
+
+
+
+
+
+ );
+
+ _renderSectionHeader = ({ section }) => {
+ return (
+
+
+ {section.title}
+
+
);
+ };
- _renderSectionHeader = ({section}) => {
- return (
-
- {section.title}
-
- );
- };
-
- _renderFooter = () => {
- if(!this.props.loading) {
- return null;
- }
-
- return (
-
- );
- };
-
- _onPressItem = (item) => {
- this.props.showEvent(item);
- };
-
-
- _formatTime(time) {
- return moment(time).format('llll');
+ _renderFooter = () => {
+ if (!this.props.loading) {
+ return null;
}
- render() {
- if (this.props.error) {
- return (
-
- { this._onPressItem(item); }}>
- Kunne ikke hente programmet...
-
-
-
-
-
- )
- }
+ return (
+
+
+
+ );
+ };
- return ( item.id}
- refreshing={this.props.refreshing}
- onRefresh={this.props.handleRefresh}
- onEndReached={this.props.handleLoadMore}
- onEndReachedThreshould={10}
- initialNumToRender={10}
- ListFooterComponent={this._renderFooter}
- style={[styles.card, styles.list]}
- ListHeaderComponent={() => { return }}
- />);
+ _onPressItem = (item) => {
+ this.props.showEvent(item);
+ };
+
+ _formatTime(time) {
+ return moment(time).format('llll');
+ }
+
+ render() {
+ if (this.props.error) {
+ return (
+
+
+ {
+ this._onPressItem(item);
+ }}
+ >
+ Kunne ikke hente programmet...
+
+
+
+
+
+
+ );
}
+
+ return (
+ item.id}
+ refreshing={this.props.refreshing}
+ onRefresh={this.props.handleRefresh}
+ onEndReached={this.props.handleLoadMore}
+ onEndReachedThreshould={10}
+ initialNumToRender={10}
+ ListFooterComponent={this._renderFooter}
+ style={[styles.card, styles.list]}
+ ListHeaderComponent={() => {
+ return ;
+ }}
+ />
+ );
+ }
}
-
const styles = StyleSheet.create({
- listItem: {
- backgroundColor: 'white',
- marginLeft: 0
- },
- listItemTitle: {
- fontSize: 14,
- },
- listItemTime: {
- fontSize: 14,
- color: '#666'
- },
- 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: {
- padding: 0,
- marginTop: 0,
- marginBottom: 0,
- backgroundColor: 'transparent',
- },
- listHeader: {
- paddingTop: 8,
- }
+ listItem: {
+ backgroundColor: 'white',
+ marginLeft: 0,
+ },
+ listItemTitle: {
+ fontSize: 14,
+ },
+ listItemTime: {
+ fontSize: 14,
+ color: '#666',
+ },
+ 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: {
+ padding: 0,
+ marginTop: 0,
+ marginBottom: 0,
+ backgroundColor: 'transparent',
+ },
+ listHeader: {
+ paddingTop: 8,
+ },
});
diff --git a/src/modules/events/EventListContainer.js b/src/modules/events/EventListContainer.js
index 8fda34a..680cc03 100644
--- a/src/modules/events/EventListContainer.js
+++ b/src/modules/events/EventListContainer.js
@@ -1,119 +1,127 @@
-import {connect} from "react-redux";
+import { connect } from 'react-redux';
-import React, {Component} from 'react';
+import React, { Component } from 'react';
import Config from 'react-native-config';
-import moment from "moment";
+import moment from 'moment';
import 'moment/locale/nb';
-import EventList from "./EventList";
+import EventList from './EventList';
moment.locale('nb');
/* Ref: https://medium.com/react-native-development/how-to-use-the-flatlist-component-react-native-basics-92c482816fe6 */
class EventListContainer extends Component {
- constructor(props) {
- super(props);
+ constructor(props) {
+ super(props);
- this.state = {
- loading: false,
- events: [],
- eventsSectioned: [],
- page: 1,
- totalPages: 0,
- error: null,
- refreshing: false,
- };
- }
-
- _formatDate(time) {
- const m = moment(time);
- if(moment().year() === m.year() ) {
- return m.format('dddd D. MMM')
- }
- return m.format('ll');
- }
-
- _toSectionFormat(events) {
- let sectioned = {};
- events.map((event) => {
- const title = this._formatDate(event.start_time);
- if( title in sectioned ) {
- sectioned[title].push(event);
- } else {
- sectioned[title] = [event];
- }
- });
-
- let sectionedList = [];
- Object.entries(sectioned).forEach(([title, section]) => {
- sectionedList.push({data: section, title: title});
- });
-
- return sectionedList;
- }
-
- handleRefresh = () => {
- this.setState({
- page: 1,
- refreshing: true,
- totalPages: 1,
- }, () => {
- this.fetchEvents()
- });
+ this.state = {
+ loading: false,
+ events: [],
+ eventsSectioned: [],
+ page: 1,
+ totalPages: 0,
+ error: null,
+ refreshing: false,
};
+ }
- handleLoadMore = () => {
- if(this.state.page >= this.state.totalPages || this.state.loading) {
- return;
- }
- this.setState({
- page: this.state.page + 1,
- }, () => {
- this.fetchEvents();
- })
- };
-
- fetchEvents() {
- const { page } = this.state;
- const url = `${Config.EVENT_API_URL}/wp-json/wp/v2/events?page=${page}&future=1`;
- this.setState({ loading: true });
-
- fetch(url)
- .then(res => {
- this.setState({totalPages: parseInt(res.headers.get('x-wp-totalpages'))});
- return res.json();
- })
- .then(res => {
- this.setState({
- events: page === 1 ? res : [...this.state.events, ...res],
- eventsSectioned: page === 1 ? this._toSectionFormat(res) : this._toSectionFormat([...this.state.events, ...res]),
- error: res.error || null,
- loading: false,
- refreshing: false
- });
-
- })
- .catch(error => {
- this.setState({ error, loading: false });
- });
+ _formatDate(time) {
+ const m = moment(time);
+ if (moment().year() === m.year()) {
+ return m.format('dddd D. MMM');
}
+ return m.format('ll');
+ }
- componentDidMount() {
+ _toSectionFormat(events) {
+ const sectioned = {};
+ events.map((event) => {
+ const title = this._formatDate(event.start_time);
+ if (title in sectioned) {
+ sectioned[title].push(event);
+ } else {
+ sectioned[title] = [event];
+ }
+ });
+
+ const sectionedList = [];
+ Object.entries(sectioned).forEach(([title, section]) => {
+ sectionedList.push({ data: section, title });
+ });
+
+ return sectionedList;
+ }
+
+ handleRefresh = () => {
+ this.setState(
+ {
+ page: 1,
+ refreshing: true,
+ totalPages: 1,
+ },
+ () => {
this.fetchEvents();
- }
+ }
+ );
+ };
- showEvent = (item) => {
- this.props.showEvent(item);
- };
-
- render() {
- return ()
+ handleLoadMore = () => {
+ if (this.state.page >= this.state.totalPages || this.state.loading) {
+ return;
}
+ this.setState(
+ {
+ page: this.state.page + 1,
+ },
+ () => {
+ this.fetchEvents();
+ }
+ );
+ };
+
+ fetchEvents() {
+ const { page } = this.state;
+ const url = `${Config.EVENT_API_URL}/wp-json/wp/v2/events?page=${page}&future=1`;
+ this.setState({ loading: true });
+
+ fetch(url)
+ .then((res) => {
+ this.setState({ totalPages: parseInt(res.headers.get('x-wp-totalpages')) });
+ return res.json();
+ })
+ .then((res) => {
+ this.setState({
+ events: page === 1 ? res : [...this.state.events, ...res],
+ eventsSectioned:
+ page === 1 ? this._toSectionFormat(res) : this._toSectionFormat([...this.state.events, ...res]),
+ error: res.error || null,
+ loading: false,
+ refreshing: false,
+ });
+ })
+ .catch((error) => {
+ this.setState({ error, loading: false });
+ });
+ }
+
+ componentDidMount() {
+ this.fetchEvents();
+ }
+
+ showEvent = (item) => {
+ this.props.showEvent(item);
+ };
+
+ render() {
+ return (
+
+ );
+ }
}
-export default connect()(EventListContainer);
\ No newline at end of file
+export default connect()(EventListContainer);
diff --git a/src/modules/login/Login.js b/src/modules/login/Login.js
index 90c2ed2..0f945da 100644
--- a/src/modules/login/Login.js
+++ b/src/modules/login/Login.js
@@ -1,162 +1,173 @@
-import React, {Component} from 'react';
-import {Linking, StyleSheet, View, Platform} from 'react-native';
-import {Container, Header, Content, Form, Item, Input, Label, Spinner, Button, Text,
- Icon} from 'native-base';
+import React, { Component } from 'react';
+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";
+import theme from '../../theme';
export default class Login extends Component {
- constructor(props) {
- super(props);
- this.state = {
- email: '',
- password: ''
- }
- }
+ constructor(props) {
+ super(props);
+ this.state = {
+ email: '',
+ password: '',
+ };
+ }
- emailInput() {
- if (this.props.loginError && this.props.loginError.username) {
- return -
-
- {
- this.refs.passwordInput._root.focus()
- }}
- />
-
;
- }
-
- return -
-
- {
- this.refs.passwordInput._root.focus()
- }}
- />
-
;
- }
-
- passwordInput() {
- if (this.props.loginError && this.props.loginError.password) {
- return -
-
-
-
- }
- return -
-
-
+ emailInput() {
+ if (this.props.loginError && this.props.loginError.username) {
+ return (
+
-
+
+ {
+ this.refs.passwordInput._root.focus();
+ }}
+ />
+ );
}
- render() {
- return (
-
-
-
-
-
- );
+ return (
+ -
+
+ {
+ this.refs.passwordInput._root.focus();
+ }}
+ />
+
+ );
+ }
+
+ passwordInput() {
+ if (this.props.loginError && this.props.loginError.password) {
+ return (
+ -
+
+
+
+ );
+ }
+ return (
+ -
+
+
+
+ );
+ }
+
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+
+ showError = () => {
+ if (this.props.loginError) {
+ const err = this.props.loginError.non_field_errors;
+ const errorFormatted = err ? err[0] : 'Feil brukernavn eller passord, prøv igjen...';
+ // TODO: Format these and highlight error fields
+ return (
+
+ {errorFormatted}
+
+ );
}
- showError = () => {
- if (this.props.loginError) {
- const err = this.props.loginError.non_field_errors;
- let errorFormatted = err ? err[0] : 'Feil brukernavn eller passord, prøv igjen...';
- // TODO: Format these and highlight error fields
- return {errorFormatted}
- }
- else {
- return
- }
- };
+ return ;
+ };
- showSpinner = () => {
- if (this.props.isLoggingIn) {
- return
- }
- };
+ showSpinner = () => {
+ if (this.props.isLoggingIn) {
+ return ;
+ }
+ };
- handleEmail = (text) => {
- this.setState({email: text})
- };
+ handleEmail = (text) => {
+ this.setState({ email: text });
+ };
- handlePassword = (text) => {
- this.setState({password: text})
- };
-
- onLoginPress = () => {
- this.props.requestLogin(this.state.email, this.state.password)
- };
+ handlePassword = (text) => {
+ this.setState({ password: text });
+ };
+ onLoginPress = () => {
+ this.props.requestLogin(this.state.email, this.state.password);
+ };
}
const styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'center',
- },
- input: {
- width: 320,
- fontSize: 20,
- height: 52,
- },
- loginButton: {
- marginBottom: 16,
- },
- forgotPasswordButton: {
- alignSelf: 'center',
- marginTop: 32,
- marginBottom: 16,
- },
- errorBox: {
- marginVertical: 10,
- },
- errorMessage: {
- textAlign: 'center',
- color: 'red',
- },
- card: theme.card,
-});
\ No newline at end of file
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ },
+ input: {
+ width: 320,
+ fontSize: 20,
+ height: 52,
+ },
+ loginButton: {
+ marginBottom: 16,
+ },
+ forgotPasswordButton: {
+ alignSelf: 'center',
+ marginTop: 32,
+ marginBottom: 16,
+ },
+ errorBox: {
+ marginVertical: 10,
+ },
+ errorMessage: {
+ textAlign: 'center',
+ color: 'red',
+ },
+ card: theme.card,
+});
diff --git a/src/modules/login/LoginContainer.js b/src/modules/login/LoginContainer.js
index 181d17a..49d11dc 100644
--- a/src/modules/login/LoginContainer.js
+++ b/src/modules/login/LoginContainer.js
@@ -1,27 +1,27 @@
-import React, {Component} from 'react';
-import {connect} from "react-redux";
-import Login from "./Login";
-import {requestLogin} from "../../api";
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import Login from './Login';
+import { requestLogin } from '../../api';
class LoginContainer extends Component {
- componentWillReceiveProps(nextProps) {
- if (this.props.isAuthenticated !== nextProps.isAuthenticated) {
- if (nextProps.isAuthenticated) {
- this.props.onLogin();
- }
- }
+ componentWillReceiveProps(nextProps) {
+ if (this.props.isAuthenticated !== nextProps.isAuthenticated) {
+ if (nextProps.isAuthenticated) {
+ this.props.onLogin();
+ }
}
+ }
- render() {
- return
- }
+ render() {
+ return ;
+ }
}
export default connect(
- (store) => ({
- isAuthenticated: store.isAuthenticated,
- isLoggingIn: store.isLoggingIn,
- loginError: store.loginError,
- }),
- {requestLogin}
+ (store) => ({
+ isAuthenticated: store.isAuthenticated,
+ isLoggingIn: store.isLoggingIn,
+ loginError: store.loginError,
+ }),
+ { requestLogin }
)(LoginContainer);
diff --git a/src/modules/membership/Membership.js b/src/modules/membership/Membership.js
index dba79e2..a95be92 100644
--- a/src/modules/membership/Membership.js
+++ b/src/modules/membership/Membership.js
@@ -1,80 +1,82 @@
-import React, {Component} from 'react';
-import {ScrollView, Text, View, StyleSheet} from "react-native";
-import {Button, Text as NBText, Spinner} from "native-base";
-
-import theme from "../../theme";
+import React, { Component } from 'react';
+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 (
-
-
-
- );
- }
-
- return (
-
-
- Hei 👋
- Her kan du bli medlem i Det Norske Studentersamfund - Chateau Neuf og ha medlemsbeviset ditt på telefonen
-
-
-
- Hva får jeg?
-
- - Minst 25% rabatt på de fleste arrangement{"\n"}
- - Gratis inngang på enkelte arrangement{"\n"}
- - Store rabatter i barene{"\n"}
- - Egne medlemsarrangement og -tilbud{"\n"}
- - Mulighet til å delta i landets eldste studentdemokrati
- Allerede medlem?
-
-
-
-
-
- )
- };
+ render() {
+ if (this.props.isFetchingUserData) {
+ return (
+
+
+
+ );
+ }
+ return (
+
+
+ Hei 👋
+
+ Her kan du bli medlem i Det Norske Studentersamfund - Chateau Neuf og ha medlemsbeviset ditt på telefonen
+
+
+
+
+ Hva får jeg?
+
+ - Minst 25% rabatt på de fleste arrangement{'\n'}- Gratis inngang på enkelte arrangement{'\n'}- Store
+ rabatter i barene{'\n'}- Egne medlemsarrangement og -tilbud{'\n'}- Mulighet til å delta i landets eldste
+ studentdemokrati
+
+ Allerede medlem?
+
+
+
+
+
+ );
+ }
}
-
const styles = StyleSheet.create({
- card: theme.card,
- paragraph: {
- textAlign: 'center',
- fontSize: 16,
- color: '#000',
- paddingBottom: 10,
- lineHeight: 25,
- },
- button: {
- marginTop: 6,
- marginBottom: 16,
- },
- em: {
- fontSize: 16,
- color: '#000',
- fontStyle: 'italic',
- textAlign: 'center',
- marginVertical: 10,
- },
- headerTitle: {
- textAlign: 'center',
- fontWeight: 'bold',
- fontSize: 20,
- color: '#000',
- paddingVertical: 10,
- lineHeight: 25,
- },
- header: {
- fontSize: 16,
- fontWeight: 'bold',
- color: '#000',
- lineHeight: 25,
- paddingLeft: 2
- },
-});
\ No newline at end of file
+ card: theme.card,
+ paragraph: {
+ textAlign: 'center',
+ fontSize: 16,
+ color: '#000',
+ paddingBottom: 10,
+ lineHeight: 25,
+ },
+ button: {
+ marginTop: 6,
+ marginBottom: 16,
+ },
+ em: {
+ fontSize: 16,
+ color: '#000',
+ fontStyle: 'italic',
+ textAlign: 'center',
+ marginVertical: 10,
+ },
+ headerTitle: {
+ textAlign: 'center',
+ fontWeight: 'bold',
+ fontSize: 20,
+ color: '#000',
+ paddingVertical: 10,
+ lineHeight: 25,
+ },
+ header: {
+ fontSize: 16,
+ fontWeight: 'bold',
+ color: '#000',
+ lineHeight: 25,
+ paddingLeft: 2,
+ },
+});
diff --git a/src/modules/membership/MembershipContainer.js b/src/modules/membership/MembershipContainer.js
index fae9bf5..f36a689 100644
--- a/src/modules/membership/MembershipContainer.js
+++ b/src/modules/membership/MembershipContainer.js
@@ -1,86 +1,89 @@
-import React, {Component} from 'react';
-import {connect} from "react-redux";
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
-import Membership from "./Membership";
-import ProofContainer from "./ProofContainer";
-import { logout } from "../../actions";
-import {requestUserData} from "../../api";
+import Membership from './Membership';
+import ProofContainer from './ProofContainer';
+import { logout } from '../../actions';
+import { requestUserData } from '../../api';
class MembershipContainer extends Component {
- constructor(props) {
- super(props);
+ constructor(props) {
+ super(props);
- this.state = {
- isFetchingUserData: props.isFetchingUserData,
- userToken: props.userToken,
- lastOrder: props.lastOrder,
+ this.state = {
+ isFetchingUserData: props.isFetchingUserData,
+ userToken: props.userToken,
+ lastOrder: props.lastOrder,
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (this.state.userToken !== nextProps.userToken) {
+ this.setState({ userToken: nextProps.userToken }, () => {
+ if (nextProps.userToken) {
+ this.fetchUser();
}
+ });
}
-
- componentWillReceiveProps(nextProps) {
- if(this.state.userToken !== nextProps.userToken) {
- this.setState({userToken: nextProps.userToken}, () => {
- if(nextProps.userToken) {
- this.fetchUser();
- }
- });
-
- }
- if(this.state.lastOrder !== nextProps.lastOrder) {
- this.setState({lastOrder: nextProps.lastOrder}, () => {
- if(nextProps.userToken) {
- this.fetchUser();
- }
- });
+ if (this.state.lastOrder !== nextProps.lastOrder) {
+ this.setState({ lastOrder: nextProps.lastOrder }, () => {
+ if (nextProps.userToken) {
+ this.fetchUser();
}
+ });
}
+ }
- fetchUser = () => {
- this.props.requestUserData(this.state.userToken)
- };
+ fetchUser = () => {
+ this.props.requestUserData(this.state.userToken);
+ };
- onLoginPress = () => {
- this.props.onLoginPress();
- };
+ onLoginPress = () => {
+ this.props.onLoginPress();
+ };
- onRegisterPress = () => {
- this.props.onRegisterPress();
- };
+ onRegisterPress = () => {
+ this.props.onRegisterPress();
+ };
- onLogoutPress = () => {
- this.props.logout();
- this.props.onLogoutPress();
- };
+ onLogoutPress = () => {
+ this.props.logout();
+ this.props.onLogoutPress();
+ };
- render() {
- if (this.props.user) {
- return ;
- }
- return ;
+ render() {
+ if (this.props.user) {
+ return (
+
+ );
}
+ return (
+
+ );
+ }
}
function storeToProps(store) {
- return {
- isAuthenticated: store.isAuthenticated,
- isFetchingUserData: store.isFetchingUserData,
- userToken: store.userToken,
- user: store.user,
- lastOrder: store.lastOrder
- };
+ return {
+ isAuthenticated: store.isAuthenticated,
+ isFetchingUserData: store.isFetchingUserData,
+ userToken: store.userToken,
+ user: store.user,
+ lastOrder: store.lastOrder,
+ };
}
export default connect(
- storeToProps,
- { requestUserData, logout }
+ storeToProps,
+ { requestUserData, logout }
)(MembershipContainer);
diff --git a/src/modules/membership/Proof.js b/src/modules/membership/Proof.js
index 2a8b343..03f7011 100644
--- a/src/modules/membership/Proof.js
+++ b/src/modules/membership/Proof.js
@@ -1,241 +1,254 @@
-import React, {Component} from 'react';
-import {Image, ScrollView, StyleSheet, Text, TouchableOpacity, View} from "react-native";
-import {Button, Text as NBText, Spinner} from 'native-base';
+import React, { Component } from 'react';
+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';
-import theme from "../../theme";
+import theme from '../../theme';
export default class Proof extends Component {
- CONFETTI_TIMEOUT = 15000;
+ CONFETTI_TIMEOUT = 15000;
- constructor(props) {
- super(props);
- this.state = {
- stopConfetti: false,
- }
+ constructor(props) {
+ super(props);
+ this.state = {
+ stopConfetti: false,
};
+ }
- componentDidUpdate () {
- if (this._confettiView && this.state.stopConfetti) {
- this._confettiView.stopConfetti();
- this.setState({stopConfetti: false});
- }
+ componentDidUpdate() {
+ if (this._confettiView && this.state.stopConfetti) {
+ this._confettiView.stopConfetti();
+ this.setState({ stopConfetti: false });
+ }
+ }
+
+ componentWillUnmount() {
+ if (this._confettiView) {
+ this._confettiView.stopConfetti();
+ }
+ }
+
+ onMembershipPress = () => {
+ this.setState({ showConfetti: true }, () => {
+ if (this._confettiView) {
+ this._confettiView.startConfetti();
+ setTimeout(
+ function() {
+ this.setState({ stopConfetti: true });
+ }.bind(this),
+ this.CONFETTI_TIMEOUT
+ );
+ }
+ });
+ };
+
+ membershipValidTo() {
+ if (!this.props.user.last_membership) {
+ return;
}
- componentWillUnmount () {
- if (this._confettiView) {
- this._confettiView.stopConfetti();
- }
+ let validTo = this.props.user.last_membership.end_date;
+ if (this.props.user.last_membership.membership_type === 'lifelong') {
+ validTo = 'Livsvarig';
}
- onMembershipPress = () => {
- this.setState({showConfetti: true}, () => {
- if(this._confettiView) {
- this._confettiView.startConfetti();
- setTimeout(function() {
- this.setState({stopConfetti: true});
- }.bind(this), this.CONFETTI_TIMEOUT);
- }
- })
- };
+ return (
+
+ Gyldig til:
+ {validTo}
+
+ );
+ }
- membershipValidTo() {
- if( !this.props.user.last_membership) {
- return;
- }
+ membershipStatus() {
+ if (!this.props.user.is_member) {
+ if (!this.props.user.last_membership) {
+ return;
+ }
- let validTo = this.props.user.last_membership.end_date;
- if (this.props.user.last_membership.membership_type === 'lifelong') {
- validTo = 'Livsvarig'
- }
-
- return (
-
- Gyldig til:
- {validTo}
-
- )
- }
-
- membershipStatus() {
- if (!this.props.user.is_member) {
- if ( !this.props.user.last_membership ) {
- return;
- }
-
- return (
-
- Utløpt
- )
- }
-
- const statusText = this.props.user.is_volunteer ? '❤️ AKTIV ❤️ ' : 'MEDLEM';
-
- return (
-
-
- {statusText}
-
- );
- }
-
- purchaseButton() {
- if (this.props.user.is_member) {
- return;
- }
-
- return (
-
- {this.props.isChargingMembership && }
-
-
- Medlemskapet er gyldig i ett år
-
- )
- }
-
- confetti() {
- if (this.props.user.is_member) {
- // Confetti!!!!
- return this._confettiView = node} confettiCount={Number.MAX_SAFE_INTEGER} />
- }
- }
-
- logo() {
- if (!this.props.user.is_member) {
- return;
- }
-
- // FIXME: URL to config
- return (
-
-
- )
- }
-
- chargeError() {
- if (!this.props.chargeError) {
- return;
- }
-
- return {this.props.chargeError}
- }
-
- render() {
- return (
-
- {this.confetti()}
-
-
- {this.membershipName()}
- {this.logo()}
- {this.membershipStatus()}
- {this.chargeError()}
- {this.purchaseButton()}
- {this.membershipValidTo()}
-
-
-
-
-
-
- )
- };
-
- membershipName() {
- let name = `${this.props.user.first_name} ${this.props.user.last_name}`;
- if(name === ' ') {
- name = this.props.user.email;
- }
- return
- {name}
+ return (
+
+ Utløpt
+ );
}
+
+ const statusText = this.props.user.is_volunteer ? '❤️ AKTIV ❤️ ' : 'MEDLEM';
+
+ return (
+
+
+ {statusText}
+
+
+ );
+ }
+
+ purchaseButton() {
+ if (this.props.user.is_member) {
+ return;
+ }
+
+ return (
+
+ {this.props.isChargingMembership && }
+
+
+ Medlemskapet er gyldig i ett år
+
+
+ );
+ }
+
+ confetti() {
+ if (this.props.user.is_member) {
+ // Confetti!!!!
+ return (this._confettiView = node)} confettiCount={Number.MAX_SAFE_INTEGER} />;
+ }
+ }
+
+ logo() {
+ if (!this.props.user.is_member) {
+ return;
+ }
+
+ // FIXME: URL to config
+ return (
+
+
+
+ );
+ }
+
+ chargeError() {
+ if (!this.props.chargeError) {
+ return;
+ }
+
+ return (
+
+ {this.props.chargeError}
+
+ );
+ }
+
+ render() {
+ return (
+
+ {this.confetti()}
+
+
+ {this.membershipName()}
+ {this.logo()}
+ {this.membershipStatus()}
+ {this.chargeError()}
+ {this.purchaseButton()}
+ {this.membershipValidTo()}
+
+
+
+
+
+
+ );
+ }
+
+ membershipName() {
+ let name = `${this.props.user.first_name} ${this.props.user.last_name}`;
+ if (name === ' ') {
+ name = this.props.user.email;
+ }
+ return (
+
+ {name}
+
+ );
+ }
}
const styles = StyleSheet.create({
- card: theme.card,
- membershipStatus: {
- marginVertical: 16,
- },
- nameText: {
- flex: 1,
- textAlign: 'center',
- fontSize: 20,
- fontWeight: 'bold',
- },
- valid: {
- backgroundColor: '#5cb85c',
- flex: 1,
- marginHorizontal: -16,
- padding: 16
- },
- validText: {
- color: 'white',
- textAlign: 'center',
- fontSize: 30,
- fontWeight: "800"
- },
- expired: {
- backgroundColor: '#d9534f',
- flex: 1,
- marginHorizontal: -16,
- padding: 16,
- marginVertical: 16,
- },
- expiredText: {
- color: 'white',
- textAlign: 'center',
- fontSize: 24
- },
- notMember: {
- backgroundColor: '#62B1F6',
- flex: 1,
- marginHorizontal: -16,
- padding: 16
- },
- notMemberText: {
- color: 'white',
- textAlign: 'center',
- fontSize: 24
- },
- validToValue: {
- fontWeight: 'bold',
- fontSize: 18,
- },
- purchaseButton: {
- marginTop: 16,
- },
- logoutButton: {
- 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
- }
-});
\ No newline at end of file
+ card: theme.card,
+ membershipStatus: {
+ marginVertical: 16,
+ },
+ nameText: {
+ flex: 1,
+ textAlign: 'center',
+ fontSize: 20,
+ fontWeight: 'bold',
+ },
+ valid: {
+ backgroundColor: '#5cb85c',
+ flex: 1,
+ marginHorizontal: -16,
+ padding: 16,
+ },
+ validText: {
+ color: 'white',
+ textAlign: 'center',
+ fontSize: 30,
+ fontWeight: '800',
+ },
+ expired: {
+ backgroundColor: '#d9534f',
+ flex: 1,
+ marginHorizontal: -16,
+ padding: 16,
+ marginVertical: 16,
+ },
+ expiredText: {
+ color: 'white',
+ textAlign: 'center',
+ fontSize: 24,
+ },
+ notMember: {
+ backgroundColor: '#62B1F6',
+ flex: 1,
+ marginHorizontal: -16,
+ padding: 16,
+ },
+ notMemberText: {
+ color: 'white',
+ textAlign: 'center',
+ fontSize: 24,
+ },
+ validToValue: {
+ fontWeight: 'bold',
+ fontSize: 18,
+ },
+ purchaseButton: {
+ marginTop: 16,
+ },
+ logoutButton: {
+ 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,
+ },
+});
diff --git a/src/modules/membership/ProofContainer.js b/src/modules/membership/ProofContainer.js
index d0e17ac..06c722a 100644
--- a/src/modules/membership/ProofContainer.js
+++ b/src/modules/membership/ProofContainer.js
@@ -1,105 +1,90 @@
-import React, {Component} from 'react';
-import {connect} from "react-redux";
-import stripe from 'tipsi-stripe'
+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";
-
+import Proof from './Proof';
+import { requestMembershipCharge } from '../../api';
stripe.setOptions({
- publishableKey: Config.STRIPE_PUBLISHABLE_KEY || '',
+ publishableKey: Config.STRIPE_PUBLISHABLE_KEY || '',
});
-
class ProofContainer extends Component {
- constructor(props) {
- super(props);
- this.state = {
- refreshing: false,
- }
+ constructor(props) {
+ super(props);
+ this.state = {
+ refreshing: false,
+ };
+ }
+
+ getPrice(membershipTypes) {
+ if (!membershipTypes) {
+ return 0;
}
- getPrice(membershipTypes) {
- if (!membershipTypes) {
- return 0;
- }
+ return membershipTypes[0].price / 100;
+ }
- return membershipTypes[0].price / 100;
- }
+ render() {
+ return (
+
+ );
+ }
- render() {
- return
- }
-
- 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? */ }
- );
+ openStripe = () => {
+ const options = {
+ prefilledInformation: {
+ email: this.props.user.email,
+ },
+ smsAutofillDisabled: true,
};
- // fetchUser = () => {
- // this.props.fetchUser().then(() => {
- // this.setState({refreshing: false});
- // });
- // };
+ const membershipTypeSlug = this.props.data.membershipTypes ? this.props.data.membershipTypes[0].slug : 'standard';
- // _onRefresh() {
- // console.log('onRefresh')
- // this.setState({refreshing: true});
- // this.fetchUser()
- // }
-
- // refreshControl() {
- // return (
- // )
- // }
+ 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? */
+ }
+ );
+ };
}
-const PROOF_QUERY = gql`{
+const PROOF_QUERY = gql`
+ {
membershipTypes(isDefault: true) {
- slug
- price
+ slug
+ price
}
-}`;
+ }
+`;
const proofContainerWithState = connect(
- (store) => ({
- userToken: store.userToken,
- isChargingMembership: store.isChargingMembership,
- chargeError: store.chargeError
- }),
- {requestMembershipCharge}
+ (store) => ({
+ userToken: store.userToken,
+ isChargingMembership: store.isChargingMembership,
+ chargeError: store.chargeError,
+ }),
+ { requestMembershipCharge }
)(ProofContainer);
export default graphql(PROOF_QUERY)(proofContainerWithState);
diff --git a/src/modules/register/UserRegister.js b/src/modules/register/UserRegister.js
index 00e89ac..71babfb 100644
--- a/src/modules/register/UserRegister.js
+++ b/src/modules/register/UserRegister.js
@@ -1,264 +1,293 @@
-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 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";
+import theme from '../../theme';
export default class UserRegister extends Component {
- constructor(props) {
- super(props);
+ constructor(props) {
+ super(props);
- this.state = {
- firstName: '',
- lastName: '',
- email: '',
- phoneNumber: '',
- password: '',
- errors: {},
- touched: new Set()
- }
+ this.state = {
+ firstName: '',
+ lastName: '',
+ email: '',
+ phoneNumber: '',
+ password: '',
+ errors: {},
+ touched: new Set(),
};
+ }
- validateForm(triggeredBy) {
- const fieldNames = ['firstName', 'lastName', 'email', 'phoneNumber', 'password'];
+ 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);
+ const errors = Object.assign({}, this.state.errors);
+ const 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;
+ /* No empty fields */
+ for (const 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];
+ }
}
- canSubmitForm() {
- return Object.keys(this.state.errors).length === 0;
- }
+ this.setState({ errors, touched });
+ }
- firstNameInput() {
- return -
-
- {
- this.setState({firstName}, () => { this.validateForm('firstName'); });
- }}
- onSubmitEditing={() => {
- this.refs.lastNameInput._root.focus()
- }}
- value={this.state.firstName}
- />
- {this.fieldHasError('firstName') && }
-
;
- }
+ fieldHasError(field) {
+ return this.state.touched.has(field) && field in this.state.errors;
+ }
- lastNameInput() {
- return -
-
- {
- this.setState({lastName}, () => { this.validateForm('lastName'); });
- }}
- onSubmitEditing={() => {
- this.refs.emailInput._root.focus()
- }}
- value={this.state.lastName}
- />
- {this.fieldHasError('lastName') && }
-
;
- }
+ canSubmitForm() {
+ return Object.keys(this.state.errors).length === 0;
+ }
- emailInput() {
- return -
-
- {
- this.setState({email}, () => { this.validateForm('email'); });
- }}
- onSubmitEditing={() => {
- this.refs.phoneInput._root.focus()
- }}
- value={this.state.email}
- />
- {this.fieldHasError('email') && }
-
;
- }
-
- phoneNumberInput() {
- return -
-
- {
- this.setState({phoneNumber}, () => { this.validateForm('phoneNumber'); });
- }}
- onSubmitEditing={() => {
- this.refs.passwordInput._root.focus()
- }}
- value={this.state.phoneNumber}
- />
- {this.fieldHasError('phoneNumber') && }
-
;
- }
-
- passwordInput() {
- return -
-
- {
- this.setState({password}, () => { this.validateForm('password'); });
- }}
- onSubmitEditing={this.onRegisterPress}
- value={this.state.password}
- />
- {this.fieldHasError('password') && }
-
- }
-
- 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 {errorFormatted}
-
- } else if (Object.keys(errors).length !== 0 && 'detail' in errors) {
- const err = errors.detail;
- let errorFormatted = err ? err : 'Kunne ikke registrere bruker, prøv igjen...';
- return {errorFormatted}
- }
-
- return
- };
-
- showFieldError = (field) => {
- if(!this.fieldHasError(field) ) {
- return;
- }
- return - {this.state.errors[field]}
;
- };
-
- showSpinner = () => {
- if (this.props.isRegisteringUser) {
- return
- }
- };
-
- render() {
- return (
-
-
-
-
-
- );
- }
-
- onRegisterPress = () => {
- if( !this.canSubmitForm() ) {
- Toast.show({
- text: 'Noen av feltene er ikke fylt ut riktig',
- position: 'bottom',
- buttonText: 'OK',
- duration: 1500,
+ firstNameInput() {
+ return (
+ -
+
+ {
+ this.setState({ firstName }, () => {
+ this.validateForm('firstName');
});
- return;
- }
+ }}
+ onSubmitEditing={() => {
+ this.refs.lastNameInput._root.focus();
+ }}
+ value={this.state.firstName}
+ />
+ {this.fieldHasError('firstName') && }
+
+ );
+ }
- this.props.onRegisterPress(
- this.state.firstName,
- this.state.lastName,
- this.state.email,
- this.state.phoneNumber,
- this.state.password,
- );
- };
+ lastNameInput() {
+ return (
+ -
+
+ {
+ this.setState({ lastName }, () => {
+ this.validateForm('lastName');
+ });
+ }}
+ onSubmitEditing={() => {
+ this.refs.emailInput._root.focus();
+ }}
+ value={this.state.lastName}
+ />
+ {this.fieldHasError('lastName') && }
+
+ );
+ }
- registerbutton() {
- const isDisabled = this.state.touched.size === 0 || this.props.isRegisteringUser || !this.canSubmitForm();
+ emailInput() {
+ return (
+ -
+
+ {
+ this.setState({ email }, () => {
+ this.validateForm('email');
+ });
+ }}
+ onSubmitEditing={() => {
+ this.refs.phoneInput._root.focus();
+ }}
+ value={this.state.email}
+ />
+ {this.fieldHasError('email') && }
+
+ );
+ }
- return ();
+ phoneNumberInput() {
+ return (
+ -
+
+ {
+ this.setState({ phoneNumber }, () => {
+ this.validateForm('phoneNumber');
+ });
+ }}
+ onSubmitEditing={() => {
+ this.refs.passwordInput._root.focus();
+ }}
+ value={this.state.phoneNumber}
+ />
+ {this.fieldHasError('phoneNumber') && }
+
+ );
+ }
+
+ passwordInput() {
+ return (
+ -
+
+ {
+ this.setState({ password }, () => {
+ this.validateForm('password');
+ });
+ }}
+ onSubmitEditing={this.onRegisterPress}
+ value={this.state.password}
+ />
+ {this.fieldHasError('password') && }
+
+ );
+ }
+
+ 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;
+ const errorFormatted = err ? err[0] : 'Kunne ikke registrere bruker, prøv igjen...';
+ return (
+
+ {errorFormatted}
+
+ );
+ }
+ if (Object.keys(errors).length !== 0 && 'detail' in errors) {
+ const err = errors.detail;
+ const errorFormatted = err || 'Kunne ikke registrere bruker, prøv igjen...';
+ return (
+
+ {errorFormatted}
+
+ );
+ }
+
+ return ;
+ };
+
+ showFieldError = (field) => {
+ if (!this.fieldHasError(field)) {
+ return;
+ }
+ return (
+ -
+ {this.state.errors[field]}
+
+ );
+ };
+
+ showSpinner = () => {
+ if (this.props.isRegisteringUser) {
+ return ;
+ }
+ };
+
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+
+ 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 (
+
+ );
+ }
}
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,
- }
+ 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,
+ },
});
diff --git a/src/modules/register/UserRegisterContainer.js b/src/modules/register/UserRegisterContainer.js
index bbf0dd6..d576b75 100644
--- a/src/modules/register/UserRegisterContainer.js
+++ b/src/modules/register/UserRegisterContainer.js
@@ -1,49 +1,50 @@
-import React, {Component} from 'react';
-import {connect} from "react-redux";
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
-import UserRegister from "./UserRegister";
-import {requestRegisterUser} from "../../api";
+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);
+ constructor(state) {
+ super(state);
+ this.state = {
+ isAuthenticated: false,
};
+ }
- render() {
- return ;
+ 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 (
+
+ );
+ }
}
function storeToProps(store) {
- const errors = store.registerError === null ? {} : store.registerError;
- return {
- isAuthenticated: store.isAuthenticated,
- isRegisteringUser: store.isRegisteringUser,
- registerError: errors
- };
+ const errors = store.registerError === null ? {} : store.registerError;
+ return {
+ isAuthenticated: store.isAuthenticated,
+ isRegisteringUser: store.isRegisteringUser,
+ registerError: errors,
+ };
}
export default connect(
- storeToProps,
- {requestRegisterUser}
+ storeToProps,
+ { requestRegisterUser }
)(UserRegisterContainer);
diff --git a/src/navigation.js b/src/navigation.js
index 4fc55ae..e04782e 100644
--- a/src/navigation.js
+++ b/src/navigation.js
@@ -1,67 +1,72 @@
-import {Platform, StyleSheet} from 'react-native';
-import {createBottomTabNavigator, createStackNavigator, createAppContainer, getActiveChildNavigationOptions} from "react-navigation";
+import { Platform, StyleSheet } from 'react-native';
+import {
+ createBottomTabNavigator,
+ createStackNavigator,
+ createAppContainer,
+ getActiveChildNavigationOptions,
+} 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";
+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: EventListScreen,
- Membership: MembershipScreen,
- About: AboutScreen,
+ EventList: EventListScreen,
+ Membership: MembershipScreen,
+ About: 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',
- }
- }),
+ tabBarPosition: 'bottom',
+ tabBarOptions: {
+ style: {
+ ...Platform.select({
+ android: {
+ backgroundColor: '#fff',
+ borderTopWidth: StyleSheet.hairlineWidth,
+ borderTopColor: 'rgba(0, 0, 0, 0.1)',
},
+ }),
},
- navigationOptions: ({ navigation, screenProps }) => ({
- // get header title from active child screen
- ...getActiveChildNavigationOptions(navigation, screenProps),
- headerStyle: {
- backgroundColor: '#f58220',
+ indicatorStyle: {
+ backgroundColor: '#f58220',
+ },
+ activeTintColor: '#f58220',
+ inactiveTintColor: '#333333',
+ showIcon: true,
+ labelStyle: {
+ fontSize: 10,
+ marginBottom: 0,
+ ...Platform.select({
+ android: {
+ fontWeight: 'bold',
},
- headerTitleStyle: {
- color: 'white',
- },
- headerTintColor: 'white',
- })
+ }),
+ },
+ },
+ navigationOptions: ({ navigation, screenProps }) => ({
+ // get header title from active child screen
+ ...getActiveChildNavigationOptions(navigation, screenProps),
+ headerStyle: {
+ backgroundColor: '#f58220',
+ },
+ headerTitleStyle: {
+ color: 'white',
+ },
+ headerTintColor: 'white',
+ }),
};
const tabNav = createBottomTabNavigator(tabBarRoutes, tabBarOptions);
const DuskenNavigation = createStackNavigator({
- Root: tabNav,
- Login: LoginScreen,
- UserRegister: UserRegisterScreen,
- EventDetail: EventDetailScreen,
+ Root: tabNav,
+ Login: LoginScreen,
+ UserRegister: UserRegisterScreen,
+ EventDetail: EventDetailScreen,
});
export default createAppContainer(DuskenNavigation);
diff --git a/src/reducers.js b/src/reducers.js
index 6eb9ea1..aaf9731 100644
--- a/src/reducers.js
+++ b/src/reducers.js
@@ -1,133 +1,133 @@
import {
- LOGIN_REQUEST,
- LOGIN_SUCCESS,
- LOGIN_FAILURE,
- LOGOUT,
- 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,
+ LOGIN_REQUEST,
+ LOGIN_SUCCESS,
+ LOGIN_FAILURE,
+ LOGOUT,
+ 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'
+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,
+ 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)] = Array.isArray(value) ? value.join('\n') : value;
- }
- return _errs
+ const _errs = {};
+ for (const [key, value] of Object.entries(errs)) {
+ _errs[snakeToCamelCase(key)] = Array.isArray(value) ? value.join('\n') : value;
+ }
+ return _errs;
}
-
-
export default function duskenApp(state = initialState, action) {
- switch (action.type) {
- /* Login */
- case LOGIN_REQUEST:
- return Object.assign({}, state, {
- isLoggingIn: true,
- loginError: null,
- });
+ switch (action.type) {
+ /* Login */
+ case LOGIN_REQUEST:
+ return Object.assign({}, state, {
+ isLoggingIn: true,
+ loginError: null,
+ });
- case LOGIN_FAILURE:
- return Object.assign({}, state, {
- isLoggingIn: false,
- loginError: action.loginError
- });
+ case LOGIN_FAILURE:
+ return Object.assign({}, state, {
+ isLoggingIn: false,
+ loginError: action.loginError,
+ });
- case LOGIN_SUCCESS:
- return Object.assign({}, state, {
- isLoggingIn: false,
- isAuthenticated: true,
- userToken: action.token
- });
+ case LOGIN_SUCCESS:
+ return Object.assign({}, state, {
+ isLoggingIn: false,
+ isAuthenticated: true,
+ userToken: action.token,
+ });
- case LOGOUT:
- return initialState;
+ case LOGOUT:
+ return initialState;
- /* User data */
- case USER_DATA_REQUEST:
- return Object.assign({}, state, {
- isFetchingUserData: true,
- userError: null
- });
+ /* User data */
+ case USER_DATA_REQUEST:
+ return Object.assign({}, state, {
+ isFetchingUserData: true,
+ userError: null,
+ });
- case USER_DATA_FAILURE:
- return Object.assign({}, state, {
- isFetchingUserData: false,
- userError: action.userError
- });
+ case USER_DATA_FAILURE:
+ return Object.assign({}, state, {
+ isFetchingUserData: false,
+ userError: action.userError,
+ });
- case USER_DATA_SUCCESS:
- return Object.assign({}, state, {
- isFetchingUserData: false,
- user: action.data,
- });
+ case USER_DATA_SUCCESS:
+ return Object.assign({}, state, {
+ isFetchingUserData: false,
+ user: action.data,
+ });
- /* Register user */
- case REGISTER_USER_REQUEST:
- return Object.assign({}, state, {
- isRegisteringUser: true,
- registerError: null,
- });
+ /* 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_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'];
+ case REGISTER_USER_SUCCESS:
+ const 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,
- });
+ 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
- });
+ /* 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_FAILURE:
+ return Object.assign({}, state, {
+ isChargingMembership: false,
+ chargeError: action.chargeError,
+ });
- case MEMBERSHIP_CHARGE_SUCCESS:
- return Object.assign({}, state, {
- isChargingMembership: false,
- lastOrder: action.data,
- });
+ case MEMBERSHIP_CHARGE_SUCCESS:
+ return Object.assign({}, state, {
+ isChargingMembership: false,
+ lastOrder: action.data,
+ });
- default:
- return state
- }
+ default:
+ return state;
+ }
}
diff --git a/src/reduxStore.js b/src/reduxStore.js
index 6142938..09d8bd3 100644
--- a/src/reduxStore.js
+++ b/src/reduxStore.js
@@ -1,26 +1,17 @@
import { applyMiddleware, createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import AsyncStorage from '@react-native-community/async-storage';
-import thunk from "redux-thunk";
-
-import rootReducer from './reducers'
+import thunk from 'redux-thunk';
+import rootReducer from './reducers';
const persistConfig = {
key: 'root',
storage: AsyncStorage,
- blacklist: [
- 'isLoggingIn',
- 'isFetchingUserData',
- 'isRegisteringUser',
- 'isChargingMembership'
- ]
+ blacklist: ['isLoggingIn', 'isFetchingUserData', 'isRegisteringUser', 'isChargingMembership'],
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
-export let store = createStore(
- persistedReducer,
- applyMiddleware(...[thunk])
-);
-export let persistor = persistStore(store);
+export const store = createStore(persistedReducer, applyMiddleware(...[thunk]));
+export const persistor = persistStore(store);
diff --git a/src/screens/AboutScreen.js b/src/screens/AboutScreen.js
index 83062ca..65a4be9 100644
--- a/src/screens/AboutScreen.js
+++ b/src/screens/AboutScreen.js
@@ -1,22 +1,21 @@
import React, { Component } from 'react';
import Icon from 'react-native-vector-icons/SimpleLineIcons';
-import {StyleProvider} from "native-base";
+import { StyleProvider } from 'native-base';
-import AboutContainer from "../modules/about/AboutContainer";
+import AboutContainer from '../modules/about/AboutContainer';
import getTheme from '../../native-base-theme/components';
export default class AboutScreen extends Component {
- static navigationOptions = {
- title: 'Om oss',
- tabBarIcon: ({ tintColor }) => (
-
- ),
- };
+ static navigationOptions = {
+ title: 'Om oss',
+ tabBarIcon: ({ tintColor }) => ,
+ };
- render() {
- return (
-
-
- );
- }
+ render() {
+ return (
+
+
+
+ );
+ }
}
diff --git a/src/screens/EventDetailScreen.js b/src/screens/EventDetailScreen.js
index aa0d687..3697aeb 100644
--- a/src/screens/EventDetailScreen.js
+++ b/src/screens/EventDetailScreen.js
@@ -1,26 +1,26 @@
import React, { Component } from 'react';
-import {StyleProvider} from "native-base";
-import EventDetail from "../modules/events/EventDetail";
+import { StyleProvider } from 'native-base';
+import EventDetail from '../modules/events/EventDetail';
import getTheme from '../../native-base-theme/components';
export default class EventDetailScreen extends Component {
- static navigationOptions = ({navigation}) => ({
- title: navigation.state.params.item.title.decoded,
- headerStyle: {
- backgroundColor: '#f58220',
- },
- headerTitleStyle: {
- color: 'white',
- },
- headerTintColor: 'white',
- });
+ static navigationOptions = ({ navigation }) => ({
+ title: navigation.state.params.item.title.decoded,
+ headerStyle: {
+ backgroundColor: '#f58220',
+ },
+ headerTitleStyle: {
+ color: 'white',
+ },
+ headerTintColor: 'white',
+ });
- render() {
- const { params } = this.props.navigation.state;
- return (
-
-
-
- );
- }
-}
\ No newline at end of file
+ render() {
+ const { params } = this.props.navigation.state;
+ return (
+
+
+
+ );
+ }
+}
diff --git a/src/screens/EventListScreen.js b/src/screens/EventListScreen.js
index 95c2ca6..a911692 100644
--- a/src/screens/EventListScreen.js
+++ b/src/screens/EventListScreen.js
@@ -1,27 +1,25 @@
import React, { Component } from 'react';
-import EventListContainer from "../modules/events/EventListContainer";
import Icon from 'react-native-vector-icons/SimpleLineIcons';
-import {StyleProvider} from "native-base";
+import { StyleProvider } from 'native-base';
+import EventListContainer from '../modules/events/EventListContainer';
import getTheme from '../../native-base-theme/components';
export default class EventsScreen extends Component {
- static navigationOptions = {
- title: 'Program',
- tabBarIcon: ({ tintColor }) => (
-
- ),
- };
+ static navigationOptions = {
+ title: 'Program',
+ tabBarIcon: ({ tintColor }) => ,
+ };
- showEvent = (item) => {
- const { navigate } = this.props.navigation;
- navigate('EventDetail', {item: item})
- };
+ showEvent = (item) => {
+ const { navigate } = this.props.navigation;
+ navigate('EventDetail', { item });
+ };
- render() {
- return (
-
-
-
- );
- }
+ render() {
+ return (
+
+
+
+ );
+ }
}
diff --git a/src/screens/LoginScreen.js b/src/screens/LoginScreen.js
index 8bbe737..a12ba87 100644
--- a/src/screens/LoginScreen.js
+++ b/src/screens/LoginScreen.js
@@ -1,30 +1,30 @@
import React, { Component } from 'react';
-import LoginContainer from "../modules/login/LoginContainer";
-import {StyleProvider} from "native-base";
+import { StyleProvider } from 'native-base';
+import LoginContainer from '../modules/login/LoginContainer';
import getTheme from '../../native-base-theme/components';
export default class LoginScreen extends Component {
- static navigationOptions = {
- title: 'Logg inn',
- headerStyle: {
- backgroundColor: '#f58220',
- },
- headerTitleStyle: {
- color: 'white',
- },
- headerTintColor: 'white',
- };
+ static navigationOptions = {
+ title: 'Logg inn',
+ headerStyle: {
+ backgroundColor: '#f58220',
+ },
+ headerTitleStyle: {
+ color: 'white',
+ },
+ headerTintColor: 'white',
+ };
- onLogin = () => {
- // This works since LoginScreen is allways navigated to from MembershipScreen
- this.props.navigation.goBack();
- };
+ onLogin = () => {
+ // This works since LoginScreen is allways navigated to from MembershipScreen
+ this.props.navigation.goBack();
+ };
- render() {
- return (
-
-
-
- )
- }
-}
\ No newline at end of file
+ render() {
+ return (
+
+
+
+ );
+ }
+}
diff --git a/src/screens/MembershipScreen.js b/src/screens/MembershipScreen.js
index a112de4..72ce1b3 100644
--- a/src/screens/MembershipScreen.js
+++ b/src/screens/MembershipScreen.js
@@ -1,37 +1,36 @@
import React, { Component } from 'react';
-import MembershipContainer from "../modules/membership/MembershipContainer";
import Icon from 'react-native-vector-icons/SimpleLineIcons';
-import {StyleProvider} from "native-base";
+import { StyleProvider } from 'native-base';
+import MembershipContainer from '../modules/membership/MembershipContainer';
import getTheme from '../../native-base-theme/components';
export default class MembershipScreen extends Component {
- static navigationOptions = {
- title: 'Medlemskap',
- tabBarIcon: ({ tintColor }) => (
-
- ),
- };
+ static navigationOptions = {
+ title: 'Medlemskap',
+ tabBarIcon: ({ tintColor }) => ,
+ };
- loginNavigate = () => {
- this.props.navigation.navigate('Login');
- };
+ loginNavigate = () => {
+ this.props.navigation.navigate('Login');
+ };
- logoutNavigate = () => {
- this.props.navigation.navigate('Membership');
- };
+ logoutNavigate = () => {
+ this.props.navigation.navigate('Membership');
+ };
- registerNavigate = () => {
- this.props.navigation.navigate('UserRegister');
- };
+ registerNavigate = () => {
+ this.props.navigation.navigate('UserRegister');
+ };
- render() {
- return (
-
-
-
- )
- }
+ render() {
+ return (
+
+
+
+ );
+ }
}
diff --git a/src/screens/UserRegisterScreen.js b/src/screens/UserRegisterScreen.js
index 0b16965..8cfc626 100644
--- a/src/screens/UserRegisterScreen.js
+++ b/src/screens/UserRegisterScreen.js
@@ -1,30 +1,30 @@
import React, { Component } from 'react';
-import UserRegisterContainer from "../modules/register/UserRegisterContainer";
-import {StyleProvider} from "native-base";
+import { StyleProvider } from 'native-base';
+import UserRegisterContainer from '../modules/register/UserRegisterContainer';
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',
- };
+ 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();
- };
+ onRegister = () => {
+ // This works since UserRegisterScreen is allways navigated to from MembershipScreen
+ this.props.navigation.goBack();
+ };
- render() {
- return (
-
-
-
- )
- }
-}
\ No newline at end of file
+ render() {
+ return (
+
+
+
+ );
+ }
+}
diff --git a/src/theme.js b/src/theme.js
index 4b3c323..80c3788 100644
--- a/src/theme.js
+++ b/src/theme.js
@@ -1,24 +1,24 @@
-import { Platform } from "react-native";
-import platform from "native-base/src/theme/variables/platform";
+import { Platform } from 'react-native';
+import platform from 'native-base/src/theme/variables/platform';
const colors = {
- danger: platform.btnDangerBg
+ 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',
+ ...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};
\ No newline at end of file
+export default { card, colors };
diff --git a/src/utils.js b/src/utils.js
index 87c209b..cd3930b 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,14 +1,14 @@
export function snakeToCamelCase(val) {
- return val.replace(/_([a-z])/g, function (g) { return g[1].toUpperCase(); });
+ return val.replace(/_([a-z])/g, function(g) {
+ return g[1].toUpperCase();
+ });
}
-export function fetchWithTimeout(url, options, timeout=10000) {
- /** Wraps fetch to allow it to time out */
- // FIXME: show timeout message in UI
- return Promise.race([
- fetch(url, options),
- new Promise((_, reject) =>
- setTimeout(() => reject(new Error('Fetch request timed out')), timeout)
- )
- ]);
+export function fetchWithTimeout(url, options, timeout = 10000) {
+ /** Wraps fetch to allow it to time out */
+ // FIXME: show timeout message in UI
+ return Promise.race([
+ fetch(url, options),
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Fetch request timed out')), timeout)),
+ ]);
}
diff --git a/yarn.lock b/yarn.lock
index 7f37a93..75cb746 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -975,6 +975,11 @@ acorn-globals@^4.1.0:
acorn "^6.0.1"
acorn-walk "^6.0.1"
+acorn-jsx@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e"
+ integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==
+
acorn-walk@^6.0.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913"
@@ -985,7 +990,7 @@ acorn@^5.5.3:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
-acorn@^6.0.1:
+acorn@^6.0.1, acorn@^6.0.7:
version "6.1.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f"
integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==
@@ -997,7 +1002,7 @@ agent-base@^4.1.0:
dependencies:
es6-promisify "^5.0.0"
-ajv@^6.5.5:
+ajv@^6.5.5, ajv@^6.9.1:
version "6.10.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==
@@ -1191,6 +1196,14 @@ argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"
+aria-query@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc"
+ integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=
+ dependencies:
+ ast-types-flow "0.0.7"
+ commander "^2.11.0"
+
arr-diff@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a"
@@ -1236,6 +1249,14 @@ array-filter@~0.0.0:
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
integrity sha1-fajPLiZijtcygDWB/SH2fKzS7uw=
+array-includes@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d"
+ integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.7.0"
+
array-map@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662"
@@ -1288,6 +1309,11 @@ assign-symbols@^1.0.0:
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+ast-types-flow@0.0.7, ast-types-flow@^0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
+ integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0=
+
astral-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
@@ -1325,6 +1351,25 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
+axobject-query@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9"
+ integrity sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==
+ dependencies:
+ ast-types-flow "0.0.7"
+
+babel-eslint@^10.0.1:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed"
+ integrity sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ "@babel/parser" "^7.0.0"
+ "@babel/traverse" "^7.0.0"
+ "@babel/types" "^7.0.0"
+ eslint-scope "3.7.1"
+ eslint-visitor-keys "^1.0.0"
+
babel-jest@^24.7.1:
version "24.7.1"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.7.1.tgz#73902c9ff15a7dfbdc9994b0b17fcefd96042178"
@@ -1628,7 +1673,7 @@ chalk@^1.1.1:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
-chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2:
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -1765,7 +1810,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
-commander@^2.19.0, commander@^2.9.0, commander@~2.20.0:
+commander@^2.11.0, commander@^2.19.0, commander@^2.9.0, commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
@@ -1840,6 +1885,11 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
+contains-path@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
+ integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
+
convert-source-map@^1.1.0, convert-source-map@^1.4.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
@@ -1908,7 +1958,7 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0:
shebang-command "^1.2.0"
which "^1.2.9"
-cross-spawn@^6.0.0:
+cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
@@ -1931,6 +1981,11 @@ cssstyle@^1.0.0:
dependencies:
cssom "0.3.x"
+damerau-levenshtein@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514"
+ integrity sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=
+
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -1947,7 +2002,7 @@ data-urls@^1.0.0:
whatwg-mimetype "^2.2.0"
whatwg-url "^7.0.0"
-debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
+debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -1961,7 +2016,7 @@ debug@^3.1.0:
dependencies:
ms "^2.1.1"
-debug@^4.1.0, debug@^4.1.1:
+debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
@@ -1995,7 +2050,7 @@ default-require-extensions@^2.0.0:
dependencies:
strip-bom "^3.0.0"
-define-properties@^1.1.2:
+define-properties@^1.1.2, define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
@@ -2064,6 +2119,28 @@ diff-sequences@^24.3.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.3.0.tgz#0f20e8a1df1abddaf4d9c226680952e64118b975"
integrity sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==
+doctrine@1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
+ integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=
+ dependencies:
+ esutils "^2.0.2"
+ isarray "^1.0.0"
+
+doctrine@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+ integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+ dependencies:
+ esutils "^2.0.2"
+
+doctrine@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+ dependencies:
+ esutils "^2.0.2"
+
dom-serializer@0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
@@ -2122,7 +2199,7 @@ email-validator@^2.0.4:
resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed"
integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ==
-emoji-regex@^7.0.1:
+emoji-regex@^7.0.1, emoji-regex@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
@@ -2171,7 +2248,7 @@ errorhandler@^1.5.0:
accepts "~1.3.3"
escape-html "~1.0.3"
-es-abstract@^1.5.1:
+es-abstract@^1.11.0, es-abstract@^1.12.0, es-abstract@^1.5.1, es-abstract@^1.7.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9"
integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==
@@ -2226,6 +2303,180 @@ escodegen@^1.9.1:
optionalDependencies:
source-map "~0.6.1"
+eslint-config-airbnb-base@^13.1.0:
+ version "13.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c"
+ integrity sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw==
+ dependencies:
+ eslint-restricted-globals "^0.1.1"
+ object.assign "^4.1.0"
+ object.entries "^1.0.4"
+
+eslint-config-airbnb@^17.1.0:
+ version "17.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz#3964ed4bc198240315ff52030bf8636f42bc4732"
+ integrity sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw==
+ dependencies:
+ eslint-config-airbnb-base "^13.1.0"
+ object.assign "^4.1.0"
+ object.entries "^1.0.4"
+
+eslint-config-prettier@^4.0.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-4.2.0.tgz#70b946b629cd0e3e98233fd9ecde4cb9778de96c"
+ integrity sha512-y0uWc/FRfrHhpPZCYflWC8aE0KRJRY04rdZVfl8cL3sEZmOYyaBdhdlQPjKZBnuRMyLVK+JUZr7HaZFClQiH4w==
+ dependencies:
+ get-stdin "^6.0.0"
+
+eslint-import-resolver-node@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a"
+ integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==
+ dependencies:
+ debug "^2.6.9"
+ resolve "^1.5.0"
+
+eslint-module-utils@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a"
+ integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==
+ dependencies:
+ debug "^2.6.8"
+ pkg-dir "^2.0.0"
+
+eslint-plugin-import@^2.16.0:
+ version "2.17.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.17.2.tgz#d227d5c6dc67eca71eb590d2bb62fb38d86e9fcb"
+ integrity sha512-m+cSVxM7oLsIpmwNn2WXTJoReOF9f/CtLMo7qOVmKd1KntBy0hEcuNZ3erTmWjx+DxRO0Zcrm5KwAvI9wHcV5g==
+ dependencies:
+ array-includes "^3.0.3"
+ contains-path "^0.1.0"
+ debug "^2.6.9"
+ doctrine "1.5.0"
+ eslint-import-resolver-node "^0.3.2"
+ eslint-module-utils "^2.4.0"
+ has "^1.0.3"
+ lodash "^4.17.11"
+ minimatch "^3.0.4"
+ read-pkg-up "^2.0.0"
+ resolve "^1.10.0"
+
+eslint-plugin-jsx-a11y@^6.2.1:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz#4ebba9f339b600ff415ae4166e3e2e008831cf0c"
+ integrity sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w==
+ dependencies:
+ aria-query "^3.0.0"
+ array-includes "^3.0.3"
+ ast-types-flow "^0.0.7"
+ axobject-query "^2.0.2"
+ damerau-levenshtein "^1.0.4"
+ emoji-regex "^7.0.2"
+ has "^1.0.3"
+ jsx-ast-utils "^2.0.1"
+
+eslint-plugin-prettier@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz#19d521e3981f69dd6d14f64aec8c6a6ac6eb0b0d"
+ integrity sha512-/PMttrarPAY78PLvV3xfWibMOdMDl57hmlQ2XqFeA37wd+CJ7WSxV7txqjVPHi/AAFKd2lX0ZqfsOc/i5yFCSQ==
+ dependencies:
+ prettier-linter-helpers "^1.0.0"
+
+eslint-plugin-react@^7.12.4:
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.13.0.tgz#bc13fd7101de67996ea51b33873cd9dc2b7e5758"
+ integrity sha512-uA5LrHylu8lW/eAH3bEQe9YdzpPaFd9yAJTwTi/i/BKTD7j6aQMKVAdGM/ML72zD6womuSK7EiGtMKuK06lWjQ==
+ dependencies:
+ array-includes "^3.0.3"
+ doctrine "^2.1.0"
+ has "^1.0.3"
+ jsx-ast-utils "^2.1.0"
+ object.fromentries "^2.0.0"
+ prop-types "^15.7.2"
+ resolve "^1.10.1"
+
+eslint-restricted-globals@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7"
+ integrity sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=
+
+eslint-scope@3.7.1:
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8"
+ integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint-scope@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
+ integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint-utils@^1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512"
+ integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==
+
+eslint-visitor-keys@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
+ integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==
+
+eslint@^5.16.0:
+ version "5.16.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea"
+ integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ ajv "^6.9.1"
+ chalk "^2.1.0"
+ cross-spawn "^6.0.5"
+ debug "^4.0.1"
+ doctrine "^3.0.0"
+ eslint-scope "^4.0.3"
+ eslint-utils "^1.3.1"
+ eslint-visitor-keys "^1.0.0"
+ espree "^5.0.1"
+ esquery "^1.0.1"
+ esutils "^2.0.2"
+ file-entry-cache "^5.0.1"
+ functional-red-black-tree "^1.0.1"
+ glob "^7.1.2"
+ globals "^11.7.0"
+ ignore "^4.0.6"
+ import-fresh "^3.0.0"
+ imurmurhash "^0.1.4"
+ inquirer "^6.2.2"
+ js-yaml "^3.13.0"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.3.0"
+ lodash "^4.17.11"
+ minimatch "^3.0.4"
+ mkdirp "^0.5.1"
+ natural-compare "^1.4.0"
+ optionator "^0.8.2"
+ path-is-inside "^1.0.2"
+ progress "^2.0.0"
+ regexpp "^2.0.1"
+ semver "^5.5.1"
+ strip-ansi "^4.0.0"
+ strip-json-comments "^2.0.1"
+ table "^5.2.3"
+ text-table "^0.2.0"
+
+espree@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a"
+ integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==
+ dependencies:
+ acorn "^6.0.7"
+ acorn-jsx "^5.0.0"
+ eslint-visitor-keys "^1.0.0"
+
esprima@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
@@ -2236,7 +2487,21 @@ esprima@^4.0.0:
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-estraverse@^4.2.0:
+esquery@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
+ integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
+ dependencies:
+ estraverse "^4.0.0"
+
+esrecurse@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+ integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
+ dependencies:
+ estraverse "^4.1.0"
+
+estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=
@@ -2439,6 +2704,11 @@ fast-deep-equal@^2.0.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+fast-diff@^1.1.2:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
+ integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
+
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
@@ -2511,6 +2781,13 @@ figures@^2.0.0:
dependencies:
escape-string-regexp "^1.0.5"
+file-entry-cache@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
+ integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
+ dependencies:
+ flat-cache "^2.0.1"
+
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@@ -2567,7 +2844,7 @@ find-cache-dir@^2.0.0:
make-dir "^2.0.0"
pkg-dir "^3.0.0"
-find-up@^2.0.0:
+find-up@^2.0.0, find-up@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
@@ -2581,6 +2858,20 @@ find-up@^3.0.0:
dependencies:
locate-path "^3.0.0"
+flat-cache@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
+ integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
+ dependencies:
+ flatted "^2.0.0"
+ rimraf "2.6.3"
+ write "1.0.3"
+
+flatted@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916"
+ integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==
+
for-in@^1.0.1, for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -2675,6 +2966,11 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+functional-red-black-tree@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
+ integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
+
gauge@~1.2.5:
version "1.2.7"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-1.2.7.tgz#e9cec5483d3d4ee0ef44b60a7d99e4935e136d93"
@@ -2710,6 +3006,11 @@ get-caller-file@^2.0.1:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+get-stdin@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
+ integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
+
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -2769,7 +3070,7 @@ global@^4.3.0:
min-document "^2.19.0"
process "~0.5.1"
-globals@^11.1.0:
+globals@^11.1.0, globals@^11.7.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
@@ -2963,6 +3264,11 @@ ignore-walk@^3.0.1:
dependencies:
minimatch "^3.0.4"
+ignore@^4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+ integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+
image-size@^0.6.0:
version "0.6.3"
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.6.3.tgz#e7e5c65bb534bd7cdcedd6cb5166272a85f75fb2"
@@ -2981,6 +3287,14 @@ import-fresh@^2.0.0:
caller-path "^2.0.0"
resolve-from "^3.0.0"
+import-fresh@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390"
+ integrity sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
import-local@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
@@ -3032,7 +3346,7 @@ inquirer@^3.0.6:
strip-ansi "^4.0.0"
through "^2.3.6"
-inquirer@^6.2.0:
+inquirer@^6.2.0, inquirer@^6.2.2:
version "6.3.1"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.3.1.tgz#7a413b5e7950811013a3db491c61d1f3b776e8e7"
integrity sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==
@@ -3284,7 +3598,7 @@ isarray@0.0.1:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
-isarray@1.0.0, isarray@~1.0.0:
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
@@ -3860,6 +4174,11 @@ json-schema@0.2.3:
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+
json-stable-stringify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
@@ -3908,6 +4227,13 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
+jsx-ast-utils@^2.0.1, jsx-ast-utils@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz#0ee4e2c971fb9601c67b5641b71be80faecf0b36"
+ integrity sha512-yDGDG2DS4JcqhA6blsuYbtsT09xL8AoLuUR2Gb5exrw7UEM19sBcOTq+YBBhrNbl0PUC4R4LnFu+dHg2HKeVvA==
+ dependencies:
+ array-includes "^3.0.3"
+
kind-of@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44"
@@ -3973,7 +4299,7 @@ leven@^2.1.0:
resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA=
-levn@~0.3.0:
+levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
@@ -4852,7 +5178,7 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
-object-keys@^1.0.12:
+object-keys@^1.0.11, object-keys@^1.0.12:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
@@ -4864,6 +5190,36 @@ object-visit@^1.0.0:
dependencies:
isobject "^3.0.0"
+object.assign@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+ integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+ dependencies:
+ define-properties "^1.1.2"
+ function-bind "^1.1.1"
+ has-symbols "^1.0.0"
+ object-keys "^1.0.11"
+
+object.entries@^1.0.4:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519"
+ integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.12.0"
+ function-bind "^1.1.1"
+ has "^1.0.3"
+
+object.fromentries@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.0.tgz#49a543d92151f8277b3ac9600f1e930b189d30ab"
+ integrity sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.11.0"
+ function-bind "^1.1.1"
+ has "^1.0.1"
+
object.getownpropertydescriptors@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
@@ -4942,7 +5298,7 @@ optimist@^0.6.1:
minimist "~0.0.1"
wordwrap "~0.0.2"
-optionator@^0.8.1:
+optionator@^0.8.1, optionator@^0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=
@@ -5060,6 +5416,13 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
parse-glob@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
@@ -5115,6 +5478,11 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+path-is-inside@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+ integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+
path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
@@ -5173,6 +5541,13 @@ pirates@^4.0.0, pirates@^4.0.1:
dependencies:
node-modules-regexp "^1.0.0"
+pkg-dir@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
+ integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=
+ dependencies:
+ find-up "^2.1.0"
+
pkg-dir@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
@@ -5229,6 +5604,18 @@ preserve@^0.2.0:
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
+prettier-linter-helpers@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
+ integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
+ dependencies:
+ fast-diff "^1.1.2"
+
+prettier@^1.17.0:
+ version "1.17.0"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.17.0.tgz#53b303676eed22cc14a9f0cec09b477b3026c008"
+ integrity sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw==
+
pretty-format@24.0.0-alpha.6:
version "24.0.0-alpha.6"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0-alpha.6.tgz#25ad2fa46b342d6278bf241c5d2114d4376fbac1"
@@ -5274,6 +5661,11 @@ progress@2.0.0:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
integrity sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=
+progress@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+ integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
promise-polyfill@^7.1.1:
version "7.1.2"
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-7.1.2.tgz#ab05301d8c28536301622d69227632269a70ca3b"
@@ -5823,6 +6215,11 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
+regexpp@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
+ integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
+
regexpu-core@^4.5.4:
version "4.5.4"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae"
@@ -5931,6 +6328,11 @@ resolve-from@^3.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
integrity sha1-six699nWiBvItuZTM17rywoYh0g=
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -5941,7 +6343,7 @@ resolve@1.1.7:
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
-resolve@^1.10.0, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.8.1:
+resolve@^1.10.0, resolve@^1.10.1, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.8.1:
version "1.10.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.1.tgz#664842ac960795bbe758221cdccda61fb64b5f18"
integrity sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==
@@ -5961,7 +6363,7 @@ ret@~0.1.10:
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
-rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3:
+rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
@@ -6222,6 +6624,15 @@ slash@^2.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
+slice-ansi@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
+ integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
+ dependencies:
+ ansi-styles "^3.2.0"
+ astral-regex "^1.0.0"
+ is-fullwidth-code-point "^2.0.0"
+
slide@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
@@ -6471,7 +6882,7 @@ strip-eof@^1.0.0:
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
-strip-json-comments@~2.0.1:
+strip-json-comments@^2.0.1, strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
@@ -6505,6 +6916,16 @@ symbol-tree@^3.2.2:
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
integrity sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=
+table@^5.2.3:
+ version "5.2.3"
+ resolved "https://registry.yarnpkg.com/table/-/table-5.2.3.tgz#cde0cc6eb06751c009efab27e8c820ca5b67b7f2"
+ integrity sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==
+ dependencies:
+ ajv "^6.9.1"
+ lodash "^4.17.11"
+ slice-ansi "^2.1.0"
+ string-width "^3.0.0"
+
tar@^4:
version "4.4.8"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
@@ -6536,6 +6957,11 @@ test-exclude@^5.2.3:
read-pkg-up "^4.0.0"
require-main-filename "^2.0.0"
+text-table@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+
throat@^4.0.0, throat@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
@@ -6977,6 +7403,13 @@ write-file-atomic@^1.2.0:
imurmurhash "^0.1.4"
slide "^1.1.5"
+write@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
+ integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
+ dependencies:
+ mkdirp "^0.5.1"
+
ws@^1.1.0, ws@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51"