From 92379b615c94f54c9cb902a492cedfa517f29160 Mon Sep 17 00:00:00 2001 From: Qolzam Date: Sat, 18 Nov 2017 19:04:31 +0700 Subject: [PATCH] Add OAuth Login facebook,google,github --- .babelrc | 11 + package.json | 213 +++++++++--------- server.js | 36 +-- src/actions/authorizeActions.ts | 22 ++ .../EmailVerificationComponent.tsx | 15 +- .../IEmailVerificationComponentProps.ts | 1 + src/components/home/HomeComponent.tsx | 3 +- src/components/login/ILoginComponentProps.ts | 8 + src/components/login/LoginComponent.tsx | 13 +- src/components/master/MasterComponent.tsx | 1 - src/core/domain/authorize/index.ts | 8 +- src/core/domain/authorize/loginResult.ts | 23 -- src/core/domain/authorize/loginUser.ts | 54 +++++ src/core/domain/authorize/oauthType.ts | 5 + .../domain/authorize/registerUserResult.ts | 24 +- src/core/domain/users/index.ts | 10 +- src/core/domain/users/profile.ts | 47 +--- src/core/domain/users/userProvider.ts | 18 ++ .../services/authorize/IAuthorizeService.ts | 9 +- .../services/authorize/AuthorizeService.ts | 122 +++++++++- .../services/users/UserService.ts | 72 ++++-- src/index.tsx | 46 +++- webpack.config.js | 16 +- 23 files changed, 513 insertions(+), 264 deletions(-) create mode 100644 .babelrc delete mode 100644 src/core/domain/authorize/loginResult.ts create mode 100644 src/core/domain/authorize/loginUser.ts create mode 100644 src/core/domain/authorize/oauthType.ts create mode 100644 src/core/domain/users/userProvider.ts diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..52c0922 --- /dev/null +++ b/.babelrc @@ -0,0 +1,11 @@ +{ + "plugins": [ + "react-hot-loader/babel", + "transform-decorators-legacy" + ], + "presets": [ + "babel-polyfill", ["env", { "modules": false }], + "react", + "stage-0" + ] +} \ No newline at end of file diff --git a/package.json b/package.json index df32d83..fd8d01d 100644 --- a/package.json +++ b/package.json @@ -1,106 +1,109 @@ { - "name": "react-social", - "version": "1.0.0", - "description": "Simple react socail app", - "main": "index.js", - "scripts": { - "test": "NODE_ENV=test karma start", - "build": "NODE_ENV=production webpack -p", - "watch": "webpack -w", - "deploy:firebase": "npm run build && firebase deploy", - "start": "npm run build && node server.js" - }, - "author": "Amir Movahedi", - "license": "MIT", - "dependencies": { - "amazon-cognito-identity-js": "^1.21.0", - "aws-sdk": "^2.132.0", - "axios": "^0.16.1", - "classnames": "^2.2.5", - "crypto-js": "^3.1.9-1", - "css-loader": "^0.28.0", - "deep-freeze-strict": "^1.1.1", - "expect": "^1.20.2", - "express": "^4.15.2", - "faker": "^4.1.0", - "file-loader": "^0.11.1", - "firebase": "^3.9.0", - "inversify": "^4.3.0", - "keycode": "^2.1.9", - "lodash": "^4.17.4", - "material-ui": "^0.19.4", - "moment": "^2.18.1", - "morgan": "^1.8.1", - "node-env-file": "^0.1.8", - "node-sass": "^4.5.2", - "prop-types": "^15.6.0", - "react": "^16.0.0", - "react-addons-test-utils": "^15.6.2", - "react-avatar-editor": "^10.3.0", - "react-dom": "^16.0.0", - "react-event-listener": "^0.5.1", - "react-linkify": "^0.2.1", - "react-parallax": "^1.4.4", - "react-redux": "^5.0.6", - "react-router": "^4.1.1 ", - "react-router-dom": "^4.1.1", - "react-router-redux": "^5.0.0-alpha.6", - "react-string-replace": "^0.4.0", - "react-tap-event-plugin": "^3.0.2", - "redux": "^3.7.2", - "redux-actions": "^2.0.3", - "redux-thunk": "^2.2.0", - "reflect-metadata": "^0.1.10", - "sass-loader": "^6.0.3", - "save": "^2.3.0", - "script-loader": "^0.7.0", - "style-loader": "^0.16.1", - "url-loader": "^0.5.8", - "uuid": "^3.0.1" - }, - "devDependencies": { - "@types/lodash": "^4.14.77", - "@types/material-ui": "^0.18.2", - "@types/node": "^8.0.33", - "@types/prop-types": "^15.5.2", - "@types/react": "^16.0.10", - "@types/react-dom": "^16.0.1", - "@types/react-event-listener": "^0.4.4", - "@types/react-redux": "^5.0.10", - "@types/react-router-dom": "^4.0.8", - "@types/react-router-redux": "^5.0.8", - "@types/react-tap-event-plugin": "0.0.30", - "@types/redux-logger": "^3.0.4", - "@types/uuid": "^3.4.3", - "@types/webpack": "^3.0.13", - "babel-core": "^6.24.1", - "babel-loader": "^7.1.2", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-polyfill": "^6.26.0", - "babel-preset-env": "^1.6.0", - "babel-preset-react": "^6.24.1", - "babel-preset-stage-0": "^6.24.1", - "css-loader": "^0.28.7", - "eslint": "^4.9.0", - "karma": "^1.6.0", - "karma-chrome-launcher": "^2.0.0", - "karma-mocha": "^1.3.0", - "karma-mocha-reporter": "^2.2.3", - "karma-sourcemap-loader": "^0.3.7", - "karma-webpack": "^2.0.3", - "mocha": "^3.2.0", - "redux-logger": "^3.0.1", - "redux-mock-store": "^1.2.3", - "source-map-loader": "^0.2.2", - "ts-loader": "^2.3.7", - "ts-node": "^3.3.0", - "tslint": "^5.7.0", - "tslint-config-standard": "^6.0.1", - "typescript": "^2.5.3", - "webpack": "^3.6.0" - }, - "engines": { - "node": "7.3.0", - "npm": "3.10.10" - } -} \ No newline at end of file + "name": "react-social", + "version": "1.0.0", + "description": "Simple react socail app", + "main": "index.js", + "scripts": { + "test": "NODE_ENV=test karma start", + "build": "NODE_ENV=production webpack -p", + "watch": "webpack -w", + "deploy:firebase": "npm run build && firebase deploy", + "start": "npm run build && node server.js" + }, + "author": "Amir Movahedi", + "license": "MIT", + "dependencies": { + "@types/react-hot-loader": "^3.0.5", + "amazon-cognito-identity-js": "^1.21.0", + "aws-sdk": "^2.132.0", + "axios": "^0.16.1", + "classnames": "^2.2.5", + "crypto-js": "^3.1.9-1", + "css-loader": "^0.28.0", + "deep-freeze-strict": "^1.1.1", + "expect": "^1.20.2", + "express": "^4.15.2", + "faker": "^4.1.0", + "file-loader": "^0.11.1", + "firebase": "^3.9.0", + "inversify": "^4.3.0", + "keycode": "^2.1.9", + "lodash": "^4.17.4", + "material-ui": "^0.19.4", + "moment": "^2.18.1", + "morgan": "^1.8.1", + "node-env-file": "^0.1.8", + "node-sass": "^4.5.2", + "prop-types": "^15.6.0", + "react": "^16.0.0", + "react-addons-test-utils": "^15.6.2", + "react-avatar-editor": "^10.3.0", + "react-dom": "^16.0.0", + "react-event-listener": "^0.5.1", + "react-hot-loader": "^3.1.3", + "react-linkify": "^0.2.1", + "react-parallax": "^1.4.4", + "react-redux": "^5.0.6", + "react-router": "^4.1.1 ", + "react-router-dom": "^4.1.1", + "react-router-redux": "^5.0.0-alpha.6", + "react-string-replace": "^0.4.0", + "react-tap-event-plugin": "^3.0.2", + "redux": "^3.7.2", + "redux-actions": "^2.0.3", + "redux-thunk": "^2.2.0", + "reflect-metadata": "^0.1.10", + "sass-loader": "^6.0.3", + "save": "^2.3.0", + "script-loader": "^0.7.0", + "style-loader": "^0.16.1", + "url-loader": "^0.5.8", + "uuid": "^3.0.1" + }, + "devDependencies": { + "@types/lodash": "^4.14.77", + "@types/material-ui": "^0.18.2", + "@types/node": "^8.0.33", + "@types/prop-types": "^15.5.2", + "@types/react": "^16.0.10", + "@types/react-dom": "^16.0.1", + "@types/react-event-listener": "^0.4.4", + "@types/react-redux": "^5.0.10", + "@types/react-router-dom": "^4.0.8", + "@types/react-router-redux": "^5.0.8", + "@types/react-tap-event-plugin": "0.0.30", + "@types/redux-logger": "^3.0.4", + "@types/uuid": "^3.4.3", + "@types/webpack": "^3.0.13", + "babel-core": "^6.24.1", + "babel-loader": "^7.1.2", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-polyfill": "^6.26.0", + "babel-preset-env": "^1.6.0", + "babel-preset-react": "^6.24.1", + "babel-preset-stage-0": "^6.24.1", + "css-loader": "^0.28.7", + "eslint": "^4.9.0", + "karma": "^1.6.0", + "karma-chrome-launcher": "^2.0.0", + "karma-mocha": "^1.3.0", + "karma-mocha-reporter": "^2.2.3", + "karma-sourcemap-loader": "^0.3.7", + "karma-webpack": "^2.0.3", + "mocha": "^3.2.0", + "redux-logger": "^3.0.1", + "redux-mock-store": "^1.2.3", + "source-map-loader": "^0.2.2", + "ts-loader": "^2.3.7", + "ts-node": "^3.3.0", + "tslint": "^5.7.0", + "tslint-config-standard": "^6.0.1", + "typescript": "^2.5.3", + "webpack": "^3.6.0", + "webpack-hot-middleware": "^2.20.0" + }, + "engines": { + "node": "7.3.0", + "npm": "3.10.10" + } +} diff --git a/server.js b/server.js index 9e4f69f..889b625 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,9 @@ var express = require('express'); var morgan = require('morgan'); var path = require('path'); +var webpack = require('webpack'); +var webpackConfig = require('./webpack.config'); +var compiler = webpack(webpackConfig); // Create our app var app = express(); @@ -10,18 +13,25 @@ const PORT = process.env.PORT || 3000; app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms')); -app.use(function (req, res, next){ - if (req.headers['x-forwarded-proto'] === 'https') { - res.redirect('http://' + req.hostname + req.url); - } else { - next(); - } +app.use(require("webpack-dev-middleware")(compiler, { + noInfo: true, + publicPath: webpackConfig.output.publicPath +})); + +app.use(require("webpack-hot-middleware")(compiler)); + +app.use(function(req, res, next) { + if (req.headers['x-forwarded-proto'] === 'https') { + res.redirect('http://' + req.hostname + req.url); + } else { + next(); + } }); app.use(function(req, res, next) { - var userAgent = req.get('User-Agent'); - console.log(userAgent); - next(); + var userAgent = req.get('User-Agent'); + console.log(userAgent); + next(); }); app.use(express.static('public')); @@ -29,11 +39,11 @@ app.use(express.static('public')); // Always return the main index.html, so react-router render the route in the client app.get('*', (req, res) => { - res.sendFile(path.resolve('public', 'index.html')); + res.sendFile(path.resolve('public', 'index.html')); }); -app.listen(PORT, function () { - console.log('Express server is up on port ' + PORT); -}); +app.listen(PORT, function() { + console.log('Express server is up on port ' + PORT); +}); \ No newline at end of file diff --git a/src/actions/authorizeActions.ts b/src/actions/authorizeActions.ts index 8f4b668..da52c7d 100644 --- a/src/actions/authorizeActions.ts +++ b/src/actions/authorizeActions.ts @@ -6,6 +6,7 @@ import { push } from 'react-router-redux' // -Import domain import { User } from 'core/domain/users' import { SocialError } from 'core/domain/common' +import { OAuthType, LoginUser } from 'core/domain/authorize' import { UserRegisterModel } from 'models/users/userRegisterModel' @@ -150,6 +151,27 @@ export const dbSendEmailVerfication = () => { } } + /** + * Login user with OAuth + */ +export const dbLoginWithOAuth = (type: OAuthType) => { + return (dispatch: any, getState: any) => { + dispatch(globalActions.showNotificationRequest()) + + return authorizeService.loginWithOAuth(type).then((result: LoginUser) => { + // Send email verification successful. + dispatch(globalActions.showNotificationSuccess()) + dispatch(login(result.uid, true)) + dispatch(push('/')) + }) + .catch((error: SocialError) => { + // An error happened. + dispatch(globalActions.showErrorMessage(error.code)) + + }) + } +} + /* _____________ CRUD State _____________ */ /** diff --git a/src/components/emailVerification/EmailVerificationComponent.tsx b/src/components/emailVerification/EmailVerificationComponent.tsx index 9028e79..e66c3fe 100644 --- a/src/components/emailVerification/EmailVerificationComponent.tsx +++ b/src/components/emailVerification/EmailVerificationComponent.tsx @@ -27,9 +27,13 @@ export class EmailVerificationComponent extends Component An verificiation email has been already sent to you. Please check your inbox. If you couldn't see the emai, please resend email verification.

-
+
+ this.props.homePage()} /> this.props.sendEmailVerification()} />
+
+
@@ -109,8 +116,8 @@ export class EmailVerificationComponent extends Component { return { - loginPage: () => { - dispatch(push('/login')) + homePage: () => { + dispatch(push('/')) }, sendEmailVerification: () => dispatch(authorizeActions.dbSendEmailVerfication()) } diff --git a/src/components/emailVerification/IEmailVerificationComponentProps.ts b/src/components/emailVerification/IEmailVerificationComponentProps.ts index f121efc..ece6338 100644 --- a/src/components/emailVerification/IEmailVerificationComponentProps.ts +++ b/src/components/emailVerification/IEmailVerificationComponentProps.ts @@ -1,4 +1,5 @@ export interface IEmailVerificationComponentProps { sendEmailVerification: () => any + homePage: () => any } diff --git a/src/components/home/HomeComponent.tsx b/src/components/home/HomeComponent.tsx index 305d00d..4dda80e 100644 --- a/src/components/home/HomeComponent.tsx +++ b/src/components/home/HomeComponent.tsx @@ -111,7 +111,8 @@ export class HomeComponent extends Component any + /** + * Login user with OAuth + * + * @memberof ILoginComponentProps + */ + loginWithOAuth: (type: OAuthType) => any + /** * Redirect to signup page * diff --git a/src/components/login/LoginComponent.tsx b/src/components/login/LoginComponent.tsx index 7a53ba9..1177408 100644 --- a/src/components/login/LoginComponent.tsx +++ b/src/components/login/LoginComponent.tsx @@ -15,6 +15,8 @@ import ActionAndroid from 'material-ui/svg-icons/action/android' import * as authorizeActions from 'actions/authorizeActions' import { ILoginComponentProps } from './ILoginComponentProps' import { ILoginComponentState } from './ILoginComponentState' +import { firebaseAuth } from 'data/firebaseClient' +import { OAuthType } from 'core/domain/authorize' // - Create Login component class export class LoginComponent extends Component { @@ -130,6 +132,8 @@ export class LoginComponent extends Component @@ -163,12 +167,16 @@ export class LoginComponent extends Component } - /> + onClick={() => loginWithOAuth(OAuthType.FACEBOOK)} + /> } - /> + onClick={() => loginWithOAuth(OAuthType.GOOGLE)} + /> } + onClick={() => loginWithOAuth(OAuthType.GITHUB)} + /> @@ -221,6 +229,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: ILoginComponentProps) => { login: (email: string, password: string) => { dispatch(authorizeActions.dbLogin(email, password)) }, + loginWithOAuth: (type: OAuthType) => dispatch(authorizeActions.dbLoginWithOAuth(type)), signupPage: () => { dispatch(push('/signup')) } diff --git a/src/components/master/MasterComponent.tsx b/src/components/master/MasterComponent.tsx index 57ac15b..d852f7c 100644 --- a/src/components/master/MasterComponent.tsx +++ b/src/components/master/MasterComponent.tsx @@ -77,7 +77,6 @@ export class MasterComponent extends Component Promise + + /** + * Login user by OAuth authentication + * + * @memberof IAuthorizeService + */ + loginWithOAuth: (type: OAuthType) => Promise } diff --git a/src/data/firebaseClient/services/authorize/AuthorizeService.ts b/src/data/firebaseClient/services/authorize/AuthorizeService.ts index b97d011..6668a5a 100644 --- a/src/data/firebaseClient/services/authorize/AuthorizeService.ts +++ b/src/data/firebaseClient/services/authorize/AuthorizeService.ts @@ -1,11 +1,13 @@ + // - Import react components import { firebaseRef, firebaseAuth } from 'data/firebaseClient' import { IAuthorizeService } from 'core/services/authorize' -import { User } from 'core/domain/users' +import { User, UserProvider } from 'core/domain/users' import { LoginUser, RegisterUserResult } from 'core/domain/authorize' import { SocialError } from 'core/domain/common' +import { OAuthType } from 'core/domain/authorize/oauthType' /** * Firbase authorize service * @@ -66,15 +68,8 @@ export class AuthorizeService implements IAuthorizeService { firebaseAuth() .createUserWithEmailAndPassword(user.email as string, user.password as string) .then((signupResult) => { - firebaseRef.child(`users/${signupResult.uid}/info`) - .set({ - ...user, - avatar: 'noImage' - }) - .then((result) => { - resolve(new RegisterUserResult(signupResult.uid)) - }) - .catch((error: any) => reject(new SocialError(error.name, error.message))) + const {uid, email, displayName, photoURL} = signupResult + this.storeUserInformation(uid,email,displayName,photoURL).then(resolve) }) .catch((error: any) => reject(new SocialError(error.code, error.message))) }) @@ -140,6 +135,11 @@ export class AuthorizeService implements IAuthorizeService { }) } + /** + * Send verfication email to user email + * + * @memberof AuthorizeService + */ public sendEmailVerification: () => Promise = () => { return new Promise((resolve,reject) => { let auth = firebaseAuth() @@ -153,9 +153,109 @@ export class AuthorizeService implements IAuthorizeService { reject(new SocialError(error.code, error.message)) }) } else { - reject(new SocialError('nullException', 'User was null')); + reject(new SocialError('authorizeService/nullException', 'User was null!')) } }) } + + public loginWithOAuth: (type: OAuthType) => Promise = (type) => { + return new Promise((resolve,reject) => { + + let provider: any + + switch (type) { + case OAuthType.GITHUB: + provider = new firebaseAuth.GithubAuthProvider() + break + case OAuthType.FACEBOOK: + provider = new firebaseAuth.FacebookAuthProvider() + break + case OAuthType.GOOGLE: + provider = new firebaseAuth.GoogleAuthProvider() + break + default: + throw new SocialError('authorizeService/loginWithOAuth','None of OAuth type is matched!') + } + firebaseAuth().signInWithPopup(provider).then((result) => { + // This gives you a GitHub Access Token. You can use it to access the GitHub API. + let token = result.credential.accessToken + // The signed-in user info. + const {user} = result + const {credential} = result + const {uid, displayName, email, photoURL} = user + const {accessToken, provider, providerId} = credential + + this.storeUserProviderData(uid,email,displayName,photoURL,providerId,provider,accessToken) + // this.storeUserInformation(uid,email,displayName,photoURL).then(resolve) + resolve(new LoginUser(user.uid,true,providerId,displayName,email,photoURL)) + + }).catch(function (error: any) { + // Handle Errors here. + let errorCode = error.code + let errorMessage = error.message + // The email of the user's account used. + let email = error.email + // The firebase.auth.AuthCredential type that was used. + let credential = error.credential + + }) + + }) + } + + /** + * Store user information + * + * @private + * @memberof AuthorizeService + */ + private storeUserInformation = (userId: string, email: string, fullName: string, avatar?: string) => { + return new Promise((resolve,reject) => { + firebaseRef.child(`users/${userId}/info`) + .set({ + userId, + avatar, + email, + fullName + }) + .then((result) => { + resolve(new RegisterUserResult(userId)) + }) + .catch((error: any) => reject(new SocialError(error.name, error.message))) + }) + } + + /** + * Store user provider information + * + * @private + * @memberof AuthorizeService + */ + private storeUserProviderData = ( + userId: string, + email: string, + fullName: string, + avatar: string, + providerId: string, + provider: string, + accessToken: string + ) => { + return new Promise((resolve,reject) => { + firebaseRef.child(`users/${userId}/providerInfo`) + .set(new UserProvider( + userId, + email, + fullName, + avatar, + providerId, + provider, + accessToken + )) + .then((result) => { + resolve(new RegisterUserResult(userId)) + }) + .catch((error: any) => reject(new SocialError(error.name, error.message))) + }) + } } diff --git a/src/data/firebaseClient/services/users/UserService.ts b/src/data/firebaseClient/services/users/UserService.ts index 6a84df4..e689269 100644 --- a/src/data/firebaseClient/services/users/UserService.ts +++ b/src/data/firebaseClient/services/users/UserService.ts @@ -2,7 +2,7 @@ import { firebaseRef, firebaseAuth } from 'data/firebaseClient' import { SocialError } from 'core/domain/common' -import { Profile } from 'core/domain/users' +import { Profile, UserProvider } from 'core/domain/users' import { IUserService } from 'core/services/users' /** @@ -15,41 +15,51 @@ import { IUserService } from 'core/services/users' export class UserService implements IUserService { public getUserProfile: (userId: string) => Promise = (userId) => { - return new Promise((resolve,reject) => { + return new Promise((resolve, reject) => { let userProfileRef: any = firebaseRef.child(`users/${userId}/info`) userProfileRef.once('value').then((snapshot: any) => { let userProfile: Profile = snapshot.val() || {} - resolve(userProfile) - }) - .catch((error: any) => { - reject(new SocialError(error.code,error.message)) + if (Object.keys(userProfile).length === 0 && userProfile.constructor === Object) { + this.getUserProviderData(userId).then((providerData: UserProvider) => { + const {avatar,fullName, email} = providerData + const userProfile = new Profile(avatar,fullName,'','',email) + resolve(userProfile) + this.updateUserProfile(userId,userProfile) + }) + } else { + resolve(userProfile) + } + }) + .catch((error: any) => { + reject(new SocialError(error.code, error.message)) + }) }) } public updateUserProfile: (userId: string, profile: Profile) - => Promise = (userId, profile) => { - return new Promise((resolve,reject) => { - let updates: any = {} + => Promise = (userId, profile) => { + return new Promise((resolve, reject) => { + let updates: any = {} - updates[`users/${userId}/info`] = profile - firebaseRef.update(updates).then(() => { - resolve() - }) - .catch((error: any) => { - reject(new SocialError(error.code,error.message)) + updates[`users/${userId}/info`] = profile + firebaseRef.update(updates).then(() => { + resolve() + }) + .catch((error: any) => { + reject(new SocialError(error.code, error.message)) + }) }) - }) - } + } public getUsersProfile: (userId: string) => Promise<{ [userId: string]: Profile }> = (userId) => { - return new Promise<{ [userId: string]: Profile }>((resolve,reject) => { + return new Promise<{ [userId: string]: Profile }>((resolve, reject) => { let usersProfileRef: any = firebaseRef.child(`users`) usersProfileRef.once('value').then((snapshot: any) => { let usersProfile: any = snapshot.val() || {} - let parsedusersProfile: {[userId: string]: Profile} = {} + let parsedusersProfile: { [userId: string]: Profile } = {} Object.keys(usersProfile).forEach((userKey) => { if (userId !== userKey) { let userInfo = usersProfile[userKey].info @@ -64,10 +74,28 @@ export class UserService implements IUserService { }) resolve(parsedusersProfile) }) - .catch((error: any) => { - reject(new SocialError(error.code,error.message)) - }) + .catch((error: any) => { + reject(new SocialError(error.code, error.message)) + }) }) } + private getUserProviderData = (userId: string) => { + return new Promise((resolve,reject) => { + let userProviderRef: any = firebaseRef.child(`users/${userId}/providerInfo`) + userProviderRef.once('value').then((snapshot: any) => { + let userProviderRef: any = firebaseRef.child(`users/${userId}/info`) + let userProvider: UserProvider = snapshot.val() || {} + console.log('----------------userProfile') + console.log(userProvider) + console.log('-----------------------') + resolve(userProvider) + }) + .catch((error: any) => { + reject(new SocialError(error.code, error.message)) + }) + }) + + } + } diff --git a/src/index.tsx b/src/index.tsx index 0493303..4f29fea 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,6 +1,7 @@ // Import external components refrence import React from 'react' import ReactDOM from 'react-dom' +import { AppContainer } from 'react-hot-loader' import injectTapEventPlugin from 'react-tap-event-plugin' import { cyan500 } from 'material-ui/styles/colors' import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme' @@ -20,7 +21,7 @@ import Master from 'components/master' // Set default data // tslint:disable-next-line:no-empty -store.subscribe(() => {}) +store.subscribe(() => { }) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 @@ -37,14 +38,35 @@ const muiTheme = getMuiTheme({ import 'applicationStyles' const supportsHistory = 'pushState' in window.history -ReactDOM.render( - - - - - {/* */} - - - , - document.getElementById('app') -) +// ReactDOM.render( +// +// +// +// +// +// +// , +// document.getElementById('app') +// ) +const render = (Component: any) => { + ReactDOM.render( + + + + + + + + + + , + document.getElementById('app') + ) +} + +render(Master) + +// Webpack Hot Module Replacement API +if (module.hot) { + module.hot.accept('components/master', () => { render(Master) }) +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 9c3e027..cb95361 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,14 +11,10 @@ try { } catch (e) { } - -var babelOptions = { - plugins: ['transform-decorators-legacy'], - presets: ['babel-polyfill', 'react', 'env', 'stage-0'] -}; - module.exports = { entry: [ + 'react-hot-loader/patch', + 'webpack-hot-middleware/client', './src/index.tsx' ], externals: { @@ -44,6 +40,7 @@ module.exports = { } }) ] : [ + new webpack.HotModuleReplacementPlugin(), new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV), @@ -58,6 +55,7 @@ module.exports = { }) ], output: { + publicPath: '/', path: path.resolve(__dirname, './public'), filename: 'bundle-v0.1.js', @@ -91,8 +89,7 @@ module.exports = { test: /\.ts(x?)$/, exclude: /node_modules/, use: [{ - loader: 'babel-loader', - options: babelOptions + loader: 'babel-loader' }, { loader: 'ts-loader', @@ -109,8 +106,7 @@ module.exports = { test: /\.js(x?)$/, exclude: /(node_modules|bower_components)/, use: { - loader: 'babel-loader', - options: babelOptions + loader: 'babel-loader' } }, {