diff --git a/.gitignore b/.gitignore index a62752dc..37b60b67 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ npm-debug.* *.p12 *.key *.mobileprovision +firebaseConfig.js diff --git a/App.js b/App.js index 7de6e0f1..39f5bbd3 100644 --- a/App.js +++ b/App.js @@ -6,6 +6,12 @@ import { createStore } from 'redux' import { Provider } from 'react-redux'; import mainReducer from './reducers/mainReducer.js' +import firebase from 'firebase'; +import { firebaseConfig } from './firebaseConfig' +if (!firebase.apps.length) { + firebase.initializeApp(firebaseConfig); +} + const store = createStore(mainReducer) export default class App extends React.Component { diff --git a/actions/actions.js b/actions/actions.js index 7ee9c0d7..caed5aa1 100644 --- a/actions/actions.js +++ b/actions/actions.js @@ -13,6 +13,8 @@ export const SELECT_TODAY = 'SELECT_TODAY' export const ADD_HABIT_TO_SETTINGS = 'ADD_HABIT_TO_SETTINGS' export const ADD_HABIT_TO_HISTORY = 'ADD_HABIT_TO_HISTORY' export const UPDATE_NOTES = 'UPDATE_NOTES' +export const UPDATE_EMAIL = 'UPDATE_EMAIL' +export const UPDATE_FIREBASE_USER = 'UPDATE_FIREBASE_USER' //Action Creators @@ -88,4 +90,14 @@ export const updateNote = (habitName, date, notes) => ({ habitName, date, notes +}) + +export const updateEmail = (email) => ({ + type: UPDATE_EMAIL, + email +}) + +export const updateFirebaseUser = (firebaseUser) => ({ + type: UPDATE_FIREBASE_USER, + firebaseUser }) \ No newline at end of file diff --git a/assets/data/dummyData.js b/assets/data/dummyData.js index 28b56192..bad262c7 100644 --- a/assets/data/dummyData.js +++ b/assets/data/dummyData.js @@ -126,6 +126,10 @@ dummyData.settings.habitSettings = { icon: 'broom' } } +dummyData.settings.user = { + email: '', + firebaseUser: {} +} diff --git a/constants/FirebaseErrors.js b/constants/FirebaseErrors.js new file mode 100644 index 00000000..b53fc866 --- /dev/null +++ b/constants/FirebaseErrors.js @@ -0,0 +1,8 @@ +export default { + DuplicateEmail: 'auth/email-already-in-use', + InvalidEmail: 'auth/invalid-email', + WeakPassword: 'auth/weak-password', + WrongPassword: 'auth/wrong-password', + UserNotFound: 'auth/user-not-found', + PermissionDenied: 'permission-denied' +} \ No newline at end of file diff --git a/navigation/AppNavigator.js b/navigation/AppNavigator.js index 111a66b0..a2245f92 100644 --- a/navigation/AppNavigator.js +++ b/navigation/AppNavigator.js @@ -10,7 +10,6 @@ import MetricsHomeScreen from '../screens/MetricsHomeScreen'; export default createAppContainer(createSwitchNavigator({ //For development purposes, place your desired screen on top (rememeber to import the screen) //i.e. (Start: MetricsSpecificHabitScreen), - Start: MainTabNavigator, Auth: AuthenticationNavigator, Main: MainTabNavigator, })); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 79a3b3bb..47e81b42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -960,6 +960,143 @@ "tiny-queue": "^0.2.1" } }, + "@firebase/app": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.3.14.tgz", + "integrity": "sha512-l/Qdi0XRbiciTTivIQsvTtgdbLeTOIjksA28ktMXVyqr/cBYFDInrNrQDh9r5/PIrE6YJjmADSO0lTAAitVTQg==", + "requires": { + "@firebase/app-types": "0.3.7", + "@firebase/util": "0.2.11", + "dom-storage": "2.1.0", + "tslib": "1.9.3", + "xmlhttprequest": "1.8.0" + } + }, + "@firebase/app-types": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.3.7.tgz", + "integrity": "sha512-rY/dw4GeCMhCv9qs0yX8dqL+DL4siQYNkUXAKujte3jVlEy0wNW+AYIkjgFB6jxO39lWDC2hFbYeFXbsFlwtUg==" + }, + "@firebase/auth": { + "version": "0.9.7", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.9.7.tgz", + "integrity": "sha512-6DyylOzHfnf1NZUOJQNs2S1HpRN8fH/O/oIByO1qTC7SqOa9Tnz4d8Lmc/Z/UfjMENCcaZbxs4p58GGYiEkjZQ==", + "requires": { + "@firebase/auth-types": "0.5.5" + } + }, + "@firebase/auth-types": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.5.5.tgz", + "integrity": "sha512-1JDDWZPBhHcW08NoZfkviVlvsPJQpk4gaUKI4sua0EXggpOn5JolXzIs7ZUXfqyLtBRbx690HZeb8orQPzXUEg==" + }, + "@firebase/database": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.3.17.tgz", + "integrity": "sha512-YHXdBOoBowRiDUPSXuc9/6zo8JOm0gEt9/NC7s9Izf3TW71N6XBLXlL13j5zEO2UEhRSDIufvWty7TiMLPir4g==", + "requires": { + "@firebase/database-types": "0.3.8", + "@firebase/logger": "0.1.10", + "@firebase/util": "0.2.11", + "faye-websocket": "0.11.1", + "tslib": "1.9.3" + } + }, + "@firebase/database-types": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.3.8.tgz", + "integrity": "sha512-n/D/0S5bIsgrJuFoBa/4F1K1/Lr9jcS3O7sBBsQJJjkZ6WsE0J8Pg5AHJargBYspLh+4x43Pa7x/r5xGjRxbgA==" + }, + "@firebase/firestore": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.1.3.tgz", + "integrity": "sha512-usijF8/S9XUXvG8q9cEEnX2s8P3X/Nf+704VbzHQGqWGiUBnYgNCmhLE/FWOUugMmdJ6XymRcTNHMGxJcKGPMQ==", + "requires": { + "@firebase/firestore-types": "1.1.1", + "@firebase/logger": "0.1.10", + "@firebase/webchannel-wrapper": "0.2.16", + "grpc": "1.19.0", + "tslib": "1.9.3" + } + }, + "@firebase/firestore-types": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-1.1.1.tgz", + "integrity": "sha512-l0hgXrUKj0kW2+unJPiNpBI2fCjvr4ELD7ikSTczP4nX61r55VHdxP0Ft1dbjOq/ICUo2kq/b8AWDeVUF2u6ow==" + }, + "@firebase/functions": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.3.tgz", + "integrity": "sha512-KQ7zYouuxx0f2mIusWtDy6MgFl8u1mwdwTkb9K+0jrViyWQ0KMRL3xcryVvXe/OEZzRmdiqYwpPp5uNQWWu19g==", + "requires": { + "@firebase/functions-types": "0.3.2", + "@firebase/messaging-types": "0.2.8", + "isomorphic-fetch": "2.2.1", + "tslib": "1.9.3" + } + }, + "@firebase/functions-types": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.3.2.tgz", + "integrity": "sha512-TZAlW+SAg8P/m/OY6XgqUufq/KPX56psGvJ58sDztsBTUWg6FzGqIU8n7lBwlYDvHD9Ca6AlGQyxCfYPHtTKzA==" + }, + "@firebase/logger": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.10.tgz", + "integrity": "sha512-JRDSP1OtvMdzhLOuNxSB47rFCsAg59tcduSjCfSrDl1p2xsiBSnclcn/0bUHIG7I0vsA3mGcAx5YuTrvWTa0wQ==" + }, + "@firebase/messaging": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.3.16.tgz", + "integrity": "sha512-NeogyiCKWZkmWU/sT081qNObq9UqUfwJor/AqqlP0sxmzaVyXm2Ds+n5QtnQ79LkJenrsf6GDQPmOrgU+lLwdQ==", + "requires": { + "@firebase/messaging-types": "0.2.8", + "@firebase/util": "0.2.11", + "tslib": "1.9.3" + } + }, + "@firebase/messaging-types": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@firebase/messaging-types/-/messaging-types-0.2.8.tgz", + "integrity": "sha512-Pz3IZqfWzb/cHBBNAjLKF+yQS7gYtwow1bwXLQhE+ptHB+2V9fEcqYhOYUpDbuE51cH/XO7qGNFVnXSveFBt9g==" + }, + "@firebase/polyfill": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@firebase/polyfill/-/polyfill-0.3.10.tgz", + "integrity": "sha512-9LmGf0LbwmAokfolFqWP1IFzLWORU90v81VQbBYgr3AYqijG5ufju7vCv1HLUznjyOsbcpGQpxg0os3rxsG55g==", + "requires": { + "core-js": "3.0.0", + "promise-polyfill": "8.1.0", + "whatwg-fetch": "2.0.4" + } + }, + "@firebase/storage": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.2.12.tgz", + "integrity": "sha512-CAN370NV7+n2iXj+O/8LqJk3aWQPasXHrIvX6V4kIzqNdlPEZuEbsE7wWZ2B2Aw8JyJw0zWYhnbU+b9IlH8S6Q==", + "requires": { + "@firebase/storage-types": "0.2.8", + "tslib": "1.9.3" + } + }, + "@firebase/storage-types": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.2.8.tgz", + "integrity": "sha512-kWSmS60OkqE0MDUmvuPNpkWUiDwV5jqzrGEFrsUixSpT8bbxHnSwmnWk5njH+yH0K4e1957JB5P/dtscK0rc7w==" + }, + "@firebase/util": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.11.tgz", + "integrity": "sha512-sYIxzZcAeK1k0fLa1gWSnIrBFtPLFN+mgTTlQ29Pe9MBppSBluKguh43ejQioDgcGwPGhrbQx8urmSiI55SrCQ==", + "requires": { + "tslib": "1.9.3" + } + }, + "@firebase/webchannel-wrapper": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.16.tgz", + "integrity": "sha512-p5QPUrmag+C77l2S7jtLlixNyBGqgeQLknzZY9ck76ipAUFNk0uJEfHJiI1Tz2pEjB7XwmoovaDhGlQDvNb5vA==" + }, "@jest/console": { "version": "24.6.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.6.0.tgz", @@ -5041,6 +5178,15 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, + "ascli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", + "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", + "requires": { + "colour": "~0.7.1", + "optjs": "~3.2.2" + } + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -5974,6 +6120,14 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, + "bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", + "requires": { + "long": "~3" + } + }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -6190,6 +6344,11 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" }, + "colour": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz", + "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=" + }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", @@ -6600,6 +6759,11 @@ "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==", "dev": true }, + "dom-storage": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/dom-storage/-/dom-storage-2.1.0.tgz", + "integrity": "sha512-g6RpyWXzl0RR6OTElHKBl7nwnK87GUyZMYC7JWsB/IA73vpqK2K6LT39x4VepLxlSsWBFrPVLnsSR5Jyty0+2Q==" + }, "dom-walk": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", @@ -7331,6 +7495,14 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, "fb-watchman": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", @@ -7500,6 +7672,21 @@ "locate-path": "^2.0.0" } }, + "firebase": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-5.9.3.tgz", + "integrity": "sha512-58ytmGOhthiMyBIQBsbqNJ/uiJswXcAOEkYeA88362sZhnrRFhzE4QWg4wWZkeDQ09gZvJRC660P8gb3tiDGdg==", + "requires": { + "@firebase/app": "0.3.14", + "@firebase/auth": "0.9.7", + "@firebase/database": "0.3.17", + "@firebase/firestore": "1.1.3", + "@firebase/functions": "0.4.3", + "@firebase/messaging": "0.3.16", + "@firebase/polyfill": "0.3.10", + "@firebase/storage": "0.2.12" + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -8135,6 +8322,423 @@ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" }, + "grpc": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.19.0.tgz", + "integrity": "sha512-xX+jZ1M3YXjngsRj/gTxB4EwM0WoWUr54DmyNq9xTeg1oSuVaTPD/PK9wnZKOJWTt1pkeFspXqwJPhddZNxHOA==", + "requires": { + "lodash.camelcase": "^4.3.0", + "lodash.clone": "^4.5.0", + "nan": "^2.0.0", + "node-pre-gyp": "^0.12.0", + "protobufjs": "^5.0.3" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.5", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.1.1", + "bundled": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "ms": { + "version": "2.0.0", + "bundled": true + }, + "needle": { + "version": "2.2.4", + "bundled": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.5", + "bundled": true + }, + "npm-packlist": { + "version": "1.1.12", + "bundled": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "sax": { + "version": "1.2.4", + "bundled": true + }, + "semver": { + "version": "5.6.0", + "bundled": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true + } + } + }, "gud": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", @@ -8320,6 +8924,11 @@ } } }, + "http-parser-js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.0.tgz", + "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==" + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -10747,6 +11356,16 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lodash.clone": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", + "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=" + }, "lodash.filter": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", @@ -10813,6 +11432,11 @@ "resolved": "https://registry.npmjs.org/lodash.zipobject/-/lodash.zipobject-4.1.3.tgz", "integrity": "sha1-s5n1q6j/YqdG9peb8gshT5ZNvvg=" }, + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -11412,8 +12036,7 @@ "nan": { "version": "2.13.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", - "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", - "optional": true + "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==" }, "nanomatch": { "version": "1.2.13", @@ -11762,6 +12385,11 @@ "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" }, + "optjs": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz", + "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4=" + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -12099,6 +12727,11 @@ "asap": "~2.0.3" } }, + "promise-polyfill": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.0.tgz", + "integrity": "sha512-OzSf6gcCUQ01byV4BgwyUCswlaQQ6gzXc23aLQWhicvfX9kfsUiUhgt3CCQej8jDnl8/PhGF31JdHX2/MzF3WA==" + }, "prompts": { "version": "0.1.14", "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz", @@ -12119,6 +12752,56 @@ "react-is": "^16.8.1" } }, + "protobufjs": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.3.tgz", + "integrity": "sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==", + "requires": { + "ascli": "~1", + "bytebuffer": "~5", + "glob": "^7.0.5", + "yargs": "^3.10.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "requires": { + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + } + } + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -14135,6 +14818,11 @@ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -14427,6 +15115,20 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", "dev": true }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "requires": { + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + }, "whatwg-encoding": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", @@ -14471,6 +15173,11 @@ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -14567,6 +15274,11 @@ "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=" }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" + }, "xpipe": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/xpipe/-/xpipe-1.0.5.tgz", diff --git a/package.json b/package.json index bf1a6736..8c10aa15 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@expo/samples": "2.1.1", "@types/jest": "^24.0.11", "expo": "^32.0.0", + "firebase": "^5.9.3", "moment": "^2.24.0", "moment-timezone": "^0.5.23", "react": "16.5.0", diff --git a/reducers/settingsReducer.js b/reducers/settingsReducer.js index cee7c000..fea9d2df 100644 --- a/reducers/settingsReducer.js +++ b/reducers/settingsReducer.js @@ -1,5 +1,5 @@ import { - ADD_HABIT_TO_SETTINGS + ADD_HABIT_TO_SETTINGS, UPDATE_EMAIL, UPDATE_FIREBASE_USER } from '../actions/actions' const settingsReducer = (state = {}, action) => { @@ -11,6 +11,20 @@ const settingsReducer = (state = {}, action) => { newState.habitSettings[habitName] = habitSettings return newState } + case UPDATE_EMAIL: { + let {email} = action + let newState = {...state} + newState.user = {...state.user} + newState.user.email = email + return newState + } + case UPDATE_FIREBASE_USER: { + let {firebaseUser} = action + let newState = {...state} + newState.user = {...state.user} + newState.user.firebaseUser = firebaseUser + return newState + } } return state } diff --git a/screens/AuthenticationHomeScreen.js b/screens/AuthenticationHomeScreen.js index 4963f497..949e256e 100644 --- a/screens/AuthenticationHomeScreen.js +++ b/screens/AuthenticationHomeScreen.js @@ -3,10 +3,17 @@ import { View, Text, StyleSheet, - TouchableOpacity + TouchableOpacity, + ActivityIndicator } from 'react-native' +import { + updateEmail, + updateFirebaseUser +} from '../actions/actions' import { connect } from 'react-redux'; import Colors from '../constants/Colors.js' +import firebase from '@firebase/app'; +import '@firebase/auth' const mapStateToProps = (state) => { return { @@ -16,7 +23,8 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { - + updateEmail: (email) => dispatch(updateEmail(email)), + updateFirebaseUser: (firebaseUser) => dispatch(updateFirebaseUser(firebaseUser)) } } @@ -27,10 +35,43 @@ class AuthenticationHomeScreen extends React.Component { constructor(props) { super(props); this.state = { - + checkingLoggedIn: true } } + + componentDidMount() { + this.checkIfLoggedIn() + } + + componentWillUnmount() { + this.unsubscribe(); + } + + checkIfLoggedIn() { + this.unsubscribe = firebase.auth().onAuthStateChanged( + (user) => { + if (user) { + //Store username and email in redux + this.props.updateFirebaseUser(user) + this.props.updateEmail(user.email) + + this.props.navigation.navigate('Main') + } + else { + this.setState({ checkingLoggedIn: false }) + } + } + ) + } + render() { + if (this.state.checkingLoggedIn) { + return ( + + + + ) + } return ( { return { @@ -19,7 +27,8 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { - + updateEmail: (email) => dispatch(updateEmail(email)), + updateFirebaseUser: (firebaseUser) => dispatch(updateFirebaseUser(firebaseUser)) } } @@ -28,13 +37,68 @@ class LoginScreen extends React.Component { header: null } - state = { - username: null, - password: null + constructor(props) { + super(props); + this.state = { + email: '', + password: '' + } + } + + login() { + if (this.confirmFields()) { + this.loginWithFirebase() + } } - login = () => { - this.props.navigation.navigate('Main') + loginWithFirebase() { + firebase.auth().signInWithEmailAndPassword(this.state.email, this.state.password).then( + ({ user }) => { + console.log("Successfully logged in.") + //Set username/email in redux + this.props.updateEmail(user.email) + this.props.updateFirebaseUser(user) + + //Navigate to profile screen as authenticated user + this.props.navigation.navigate('Main') + }, + (error) => { + console.log('Login failed.') + if (error.code === firebaseErrors.UserNotFound) { + AlertIOS.alert('', `No user found with the email ${this.state.email}.`) + this.clearFields() + } + else if (error.code === firebaseErrors.WrongPassword) { + AlertIOS.alert('', `Incorrect password for ${this.state.email}.`) + this.clearFields(passwordsOnly = true) + } + else if (error.code === firebaseErrors.InvalidEmail) { + AlertIOS.alert('', "Invalid email address.") + this.clearFields(); + } + } + ) + } + + confirmFields() { + if (this.state.email === '') { + AlertIOS.alert('', "Please enter a email.") + return false; + } + if (this.state.password === '') { + AlertIOS.alert('', "Please enter a password.") + return false + } + return true + } + + clearFields(passwordsOnly = false) { + if (passwordsOnly) { + this.setState({ password: ''}) + } + else { + this.setState({ email: '', password: ''}) + } } render() { @@ -53,13 +117,14 @@ class LoginScreen extends React.Component { > this.setState({ username })} + onChangeText={text => this.setState({ email: text })} onSubmitEditing={() => this.refs.passwordInput.focus()} + value={this.state.email} /> this.setState({ password })} onSubmitEditing={() => this.login()} + value={this.state.password} /> { return { - + user: state.settings.user } } const mapDispatchToProps = (dispatch) => { return { - + updateEmail: (email) => dispatch(updateEmail(email)), + updateFirebaseUser: (firebaseUser) => dispatch(updateFirebaseUser(firebaseUser)) } } @@ -24,14 +31,32 @@ class SettingsHomeScreen extends React.Component { static navigationOptions = { title: 'Settings' } + + signOut() { + firebase.auth().signOut() + console.log("Signed Out") + this.props.updateEmail('') + this.props.updateFirebaseUser({}) + this.props.navigation.navigate('Auth') + } + render() { return ( this.props.navigation.navigate('Auth')} + onPress={() => { + if (this.props.user.email === '') { + this.props.navigation.navigate('Auth') + } + else { + this.signOut() + } + }} > - Logout + + {this.props.user.email === '' ? 'Login/Sign Up' : 'Sign Out'} + diff --git a/screens/SignUpScreen.js b/screens/SignUpScreen.js index e5308028..b5894b66 100644 --- a/screens/SignUpScreen.js +++ b/screens/SignUpScreen.js @@ -5,11 +5,19 @@ import { StyleSheet, TextInput, TouchableOpacity, + AlertIOS, KeyboardAvoidingView } from 'react-native' import { connect } from 'react-redux'; import Colors from '../constants/Colors.js'; +import firebaseErrors from '../constants/FirebaseErrors' +import { + updateEmail, + updateFirebaseUser +} from '../actions/actions' import Ionicons from '@expo/vector-icons/Ionicons'; +import firebase from '@firebase/app'; +import '@firebase/auth' const mapStateToProps = (state) => { return { @@ -19,7 +27,8 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { - + updateEmail: (email) => dispatch(updateEmail(email)), + updateFirebaseUser: (firebaseUser) => dispatch(updateFirebaseUser(firebaseUser)) } } @@ -28,15 +37,78 @@ class SignUpScreen extends React.Component { header: null } - state = { - email: null, - username: null, - password: null, - repeatPassword: null + constructor(props) { + super(props); + this.state = { + email: '', + password: '', + repeatPassword: '' + } + } + + signUp() { + if (this.confirmFields()) { + this.signUpWithFirebase() + } + } + + signUpWithFirebase() { + let strippedEmail = this.state.email.replace(/^\s+|\s+$/g, '').toLowerCase() + firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password).then( + ({ user }) => { + console.log("Successfully created an account.") + + this.props.updateEmail(strippedEmail) + this.props.updateFirebaseUser(user) + + this.props.navigation.navigate('Main') + }, + (error) => { + console.log("Error occured while creating an account.") + console.log(error) + if (error.code === firebaseErrors.DuplicateEmail) { + AlertIOS.alert('', "The email address provided has an existing account.") + this.clearFields() + } + else if (error.code === firebaseErrors.InvalidEmail) { + AlertIOS.alert('', "Invalid email address.") + this.clearFields(); + } + else if (error.code === firebaseErrors.WeakPassword) { + AlertIOS.alert('', "The password must be at least 6 characters.") + this.clearFields(passwordsOnly = true) + } + } + ) + } + + confirmFields() { + if (this.state.email === '') { + AlertIOS.alert('', 'Please enter an email address!') + return false; + } + if (this.state.password === '') { + AlertIOS.alert('', "Please enter a password.") + return false + } + if (this.state.repeatPassword === '') { + AlertIOS.alert('', "Please re-enter your password.") + return false + } + if (this.state.password != this.state.repeatPassword) { + AlertIOS.alert("Passwords do not match.") + return false + } + return true } - signUp = () => { - this.props.navigation.navigate('Main') + clearFields(passwordsOnly = false) { + if (passwordsOnly) { + this.setState({ password: '', repeatPassword: '' }) + } + else { + this.setState({ email: '', password: '', repeatPassword: '' }) + } } render() { @@ -55,15 +127,16 @@ class SignUpScreen extends React.Component { > this.setState({ username })} + ref="emailInput" + onChangeText={text => this.setState({ email: text })} onSubmitEditing={() => this.refs.passwordInput.focus()} + value={this.state.email} /> this.setState({ password })} onSubmitEditing={() => this.refs.repeatPasswordInput.focus()} + value={this.state.password} /> this.setState({ repeatPassword })} onSubmitEditing={() => this.signUp()} + value={this.state.repeatPassword} + />