From 55789967eb983709e7eb170d3cd6502d171f086d Mon Sep 17 00:00:00 2001 From: Qolzam Date: Sun, 12 Nov 2017 15:31:54 +0700 Subject: [PATCH] Add reset password & UI change --- .gitignore | 2 +- package.json | 208 +++++++------- public/index.html | 229 ++++++++------- src/actions/authorizeActions.ts | 22 ++ src/actions/commentActions.ts | 2 +- src/components/login/LoginComponent.tsx | 38 ++- src/components/master/MasterComponent.tsx | 2 + .../IRestPasswordComponentProps.ts | 16 ++ .../IRestPasswordComponentState.ts | 20 ++ .../resetPassword/RestPasswordComponent.tsx | 173 ++++++++++++ src/components/resetPassword/index.ts | 2 + src/components/signup/SignupComponent.tsx | 2 +- .../services/authorize/IAuthorizeService.ts | 9 +- src/core/services/comments/ICommentService.ts | 2 +- src/data/firebaseClient/index.ts | 1 + .../services/authorize/AuthorizeService.ts | 19 +- .../services/circles/CircleService.ts | 16 +- .../services/comments/CommentService.ts | 6 +- src/styles/app.scss | 6 +- src/styles/base/_animate.scss | 29 ++ src/styles/base/_icon.scss | 38 +++ webpack.config.js | 263 +++++++++--------- 22 files changed, 731 insertions(+), 374 deletions(-) create mode 100644 src/components/resetPassword/IRestPasswordComponentProps.ts create mode 100644 src/components/resetPassword/IRestPasswordComponentState.ts create mode 100644 src/components/resetPassword/RestPasswordComponent.tsx create mode 100644 src/components/resetPassword/index.ts create mode 100644 src/styles/base/_icon.scss diff --git a/.gitignore b/.gitignore index d3325e4..ad9d66a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules/ -public/bundle.js +public/bundle*.js config/ .vscode/ src/data/awsClient diff --git a/package.json b/package.json index 368b31c..df32d83 100644 --- a/package.json +++ b/package.json @@ -1,104 +1,106 @@ { - "name": "react-social", - "version": "1.0.0", - "description": "Simple react socail app", - "main": "index.js", - "scripts": { - "test": "NODE_ENV=test karma start", - "build": "webpack", - "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" - } -} + "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 diff --git a/public/index.html b/public/index.html index eab425a..d463c7c 100644 --- a/public/index.html +++ b/public/index.html @@ -2,130 +2,127 @@ - - - - + + + + -
-
-
-
-
-
-

Green Open Social

+
+
+
+
+
+
+

Green Open Social

+
-
- + \ No newline at end of file diff --git a/src/actions/authorizeActions.ts b/src/actions/authorizeActions.ts index da639a2..dce0cff 100644 --- a/src/actions/authorizeActions.ts +++ b/src/actions/authorizeActions.ts @@ -107,6 +107,28 @@ export const dbUpdatePassword = (newPassword: string) => { } } + /** + * Reset user's password + * @param {string} newPassword + */ +export const dbResetPassword = (email: string) => { + return (dispatch: any, getState: any) => { + dispatch(globalActions.showNotificationRequest()) + + return authorizeService.resetPassword(email).then(() => { + + // Reset password successful. + dispatch(globalActions.showNotificationSuccess()) + dispatch(push('/login')) + }) + .catch((error: SocialError) => { + // An error happened. + dispatch(globalActions.showErrorMessage(error.code)) + + }) + } +} + /* _____________ CRUD State _____________ */ /** diff --git a/src/actions/commentActions.ts b/src/actions/commentActions.ts index 5b4a5b9..0bc8513 100644 --- a/src/actions/commentActions.ts +++ b/src/actions/commentActions.ts @@ -107,7 +107,7 @@ export const dbUpdateComment = (id: string, postId: string, text: string) => { userId: uid } - return commentService.updateComment(uid,postId,updatedComment) + return commentService.updateComment(id,postId,updatedComment) .then(() => { dispatch(updateComment( id, postId, text)) dispatch(globalActions.hideTopLoading()) diff --git a/src/components/login/LoginComponent.tsx b/src/components/login/LoginComponent.tsx index 0dc9b12..7a53ba9 100644 --- a/src/components/login/LoginComponent.tsx +++ b/src/components/login/LoginComponent.tsx @@ -7,6 +7,9 @@ import Paper from 'material-ui/Paper' import TextField from 'material-ui/TextField' import RaisedButton from 'material-ui/RaisedButton' import FlatButton from 'material-ui/FlatButton' +import FontIcon from 'material-ui/FontIcon' +import Divider from 'material-ui/Divider' +import ActionAndroid from 'material-ui/svg-icons/action/android' // - Import actions import * as authorizeActions from 'actions/authorizeActions' @@ -16,6 +19,24 @@ import { ILoginComponentState } from './ILoginComponentState' // - Create Login component class export class LoginComponent extends Component { + styles = { + singinOptions: { + paddingBottom: 10 + }, + divider: { + marginBottom: 10, + marginTop: 15 + }, + restPassword: { + lineHeight: 6, + fontWeight: 100, + fontSize: 'small' + }, + restPasswordLink: { + color: '#0095ff' + } + } + /** * Component constructor * @param {object} props is an object properties of component @@ -30,6 +51,7 @@ export class LoginComponent extends ComponentSign in + }} className='zoomOutLCorner animated'>Sign in
+
+
} + /> + } + /> + } + /> + + - + Have you forgot your password? reset your password diff --git a/src/components/master/MasterComponent.tsx b/src/components/master/MasterComponent.tsx index b50e569..3e8d280 100644 --- a/src/components/master/MasterComponent.tsx +++ b/src/components/master/MasterComponent.tsx @@ -11,6 +11,7 @@ import LinearProgress from 'material-ui/LinearProgress' import Home from 'components/home' import Signup from 'components/signup' import Login from 'components/login' +import ResetPassword from 'components/resetPassword' import Setting from 'components/setting' import MasterLoading from 'components/masterLoading' import { IMasterComponentProps } from './IMasterComponentProps' @@ -133,6 +134,7 @@ export class MasterComponent extends Component + { console.log('this.props.authed: ', this.props.authed, 'this.props: ', this.props) return ( diff --git a/src/components/resetPassword/IRestPasswordComponentProps.ts b/src/components/resetPassword/IRestPasswordComponentProps.ts new file mode 100644 index 0000000..4dec803 --- /dev/null +++ b/src/components/resetPassword/IRestPasswordComponentProps.ts @@ -0,0 +1,16 @@ +export interface IRestPasswordComponentProps { + + /** + * Reset password + * + * @memberof IRestPasswordComponentProps + */ + resetPassword: (email: string) => any + + /** + * Redirect to login page + * + * @memberof IRestPasswordComponentProps + */ + loginPage: () => void +} diff --git a/src/components/resetPassword/IRestPasswordComponentState.ts b/src/components/resetPassword/IRestPasswordComponentState.ts new file mode 100644 index 0000000..694438e --- /dev/null +++ b/src/components/resetPassword/IRestPasswordComponentState.ts @@ -0,0 +1,20 @@ + +export interface IRestPasswordComponentState { + + /** + * Email input value + * + * @type {string} + * @memberof IRestPasswordComponentState + */ + emailInput: string + + /** + * Email input error text + * + * @type {string} + * @memberof IRestPasswordComponentState + */ + emailInputError: string + +} diff --git a/src/components/resetPassword/RestPasswordComponent.tsx b/src/components/resetPassword/RestPasswordComponent.tsx new file mode 100644 index 0000000..b7111ac --- /dev/null +++ b/src/components/resetPassword/RestPasswordComponent.tsx @@ -0,0 +1,173 @@ +// - Import external components +import React, { Component } from 'react' +import { connect } from 'react-redux' +import { NavLink, withRouter } from 'react-router-dom' +import { push } from 'react-router-redux' +import Paper from 'material-ui/Paper' +import TextField from 'material-ui/TextField' +import RaisedButton from 'material-ui/RaisedButton' +import FlatButton from 'material-ui/FlatButton' +import { firebaseRef, firebaseAuth } from 'data/firebaseClient' + +// - Import actions +import * as authorizeActions from 'actions/authorizeActions' +import { IRestPasswordComponentProps } from './IRestPasswordComponentProps' +import { IRestPasswordComponentState } from './IRestPasswordComponentState' + +/** + * Create component class + * + * @export + * @class RestPasswordComponent + * @extends {Component} + */ +export class RestPasswordComponent extends Component { + + /** + * Component constructor + * @param {object} props is an object properties of component + */ + constructor (props: IRestPasswordComponentProps) { + super(props) + + this.state = { + emailInput: '', + emailInputError: '' + + } + // Binding function to `this` + this.handleForm = this.handleForm.bind(this) + + } + + /** + * Handle data on input change + * @param {event} evt is an event of inputs of element on change + */ + handleInputChange = (event: any) => { + const target = event.target + const value = target.type === 'checkbox' ? target.checked : target.value + const name = target.name + this.setState({ + [name]: value + }) + + } + + /** + * Handle register form + */ + handleForm = () => { + + let error = false + if (this.state.emailInput === '') { + this.setState({ + emailInputError: 'This field is required' + }) + + return + } + + this.props.resetPassword(this.state.emailInput) + } + + /** + * Reneder component DOM + * @return {react element} return the DOM which rendered by component + */ + render () { + + const paperStyle = { + minHeight: 370, + width: 450, + textAlign: 'center', + display: 'block', + margin: 'auto' + } + return ( +
+ +

Green

+ +
+ +
+
+ +

Reset Password

+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ ) + } +} + +/** + * Map dispatch to props + * @param {func} dispatch is the function to dispatch action to reducers + * @param {object} ownProps is the props belong to component + * @return {object} props of component + */ +const mapDispatchToProps = (dispatch: Function, ownProps: IRestPasswordComponentProps) => { + return { + loginPage: () => { + dispatch(push('/login')) + }, + resetPassword: (emailAddress: string) => dispatch(authorizeActions.dbResetPassword(emailAddress)) + } +} + +/** + * Map state to props + * @param {object} state is the obeject from redux store + * @param {object} ownProps is the props belong to component + * @return {object} props of component + */ +const mapStateToProps = (state: any, ownProps: IRestPasswordComponentProps) => { + return { + + } +} + +// - Connect component to redux store +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(RestPasswordComponent as any)) diff --git a/src/components/resetPassword/index.ts b/src/components/resetPassword/index.ts new file mode 100644 index 0000000..cc9af07 --- /dev/null +++ b/src/components/resetPassword/index.ts @@ -0,0 +1,2 @@ +import RestPasswordComponent from './RestPasswordComponent' +export default RestPasswordComponent diff --git a/src/components/signup/SignupComponent.tsx b/src/components/signup/SignupComponent.tsx index 780e0e3..4d2e771 100644 --- a/src/components/signup/SignupComponent.tsx +++ b/src/components/signup/SignupComponent.tsx @@ -193,7 +193,7 @@ export class SignupComponent extends ComponentSign up + margin: 0}} className='zoomOutLCorner animated'>Sign up void) + onAuthStateChanged: (callBack: (user: User) => void) => void + + /** + * Reset user password + * + * @memberof IAuthorizeService + */ + resetPassword: (email: string) => Promise } diff --git a/src/core/services/comments/ICommentService.ts b/src/core/services/comments/ICommentService.ts index da41927..cb9aff3 100644 --- a/src/core/services/comments/ICommentService.ts +++ b/src/core/services/comments/ICommentService.ts @@ -12,7 +12,7 @@ export interface ICommentService { addComment: (postId: string, comment: Comment) => Promise getComments: (callback: (resultComments: { [postId: string]: { [commentId: string]: Comment } }) => void) => void - updateComment: (userId: string, postId: string, comment: Comment) => Promise + updateComment: (commentId: string, postId: string, comment: Comment) => Promise deleteComment: (commentId: string, postId: string) => Promise } diff --git a/src/data/firebaseClient/index.ts b/src/data/firebaseClient/index.ts index 3f53585..284178d 100644 --- a/src/data/firebaseClient/index.ts +++ b/src/data/firebaseClient/index.ts @@ -12,6 +12,7 @@ try { messagingSenderId: process.env.MESSAGING_SENDER_ID } + console.log(firebase) firebase.initializeApp(config) } catch (error) { console.log('=========Firebase initializer==============') diff --git a/src/data/firebaseClient/services/authorize/AuthorizeService.ts b/src/data/firebaseClient/services/authorize/AuthorizeService.ts index d8bf76f..5f1e101 100644 --- a/src/data/firebaseClient/services/authorize/AuthorizeService.ts +++ b/src/data/firebaseClient/services/authorize/AuthorizeService.ts @@ -108,8 +108,25 @@ export class AuthorizeService implements IAuthorizeService { * * @memberof IAuthorizeService */ - onAuthStateChanged: (callBack: (user: User) => void) => any = (callBack) => { + public onAuthStateChanged: (callBack: (user: User) => void) => any = (callBack) => { firebaseAuth().onAuthStateChanged(callBack) } + /** + * Reset user password + * + * @memberof AuthorizeService + */ + public resetPassword: (email: string) => Promise = (email) => { + return new Promise((resolve,reject) => { + let auth = firebaseAuth() + + auth.sendPasswordResetEmail(email).then(function () { + resolve() + }).catch((error: any) => { + // An error happened. + reject(new SocialError(error.code, error.message)) + }) + }) + } } diff --git a/src/data/firebaseClient/services/circles/CircleService.ts b/src/data/firebaseClient/services/circles/CircleService.ts index 69ed598..c893b08 100644 --- a/src/data/firebaseClient/services/circles/CircleService.ts +++ b/src/data/firebaseClient/services/circles/CircleService.ts @@ -18,7 +18,7 @@ export class CircleService implements ICircleService { public addCircle: (userId: string, circle: Circle) => Promise = (userId, circle) => { return new Promise((resolve,reject) => { - let circleRef = firebaseRef.child(`userCircles/${userId}/circles`).push(circle) + let circleRef = firebaseRef.child(`users/${userId}/circles`).push(circle) circleRef.then(() => { resolve(circleRef.key as string) }) @@ -35,8 +35,8 @@ export class CircleService implements ICircleService { return new Promise((resolve,reject) => { let updates: any = {} - updates[`userCircles/${userId}/circles/${circleId}/users/${userFollowingId}`] = userCircle - updates[`userCircles/${userFollowingId}/circles/-Followers/users/${userId}`] = userFollower + updates[`users/${userId}/circles/${circleId}/users/${userFollowingId}`] = userCircle + updates[`users/${userFollowingId}/circles/-Followers/users/${userId}`] = userFollower firebaseRef.update(updates).then(() => { resolve() @@ -52,8 +52,8 @@ export class CircleService implements ICircleService { return new Promise((resolve,reject) => { let updates: any = {} - updates[`userCircles/${userId}/circles/${circleId}/users/${userFollowingId}`] = null - updates[`userCircles/${userFollowingId}/circles/-Followers/users/${userId}`] = null + updates[`users/${userId}/circles/${circleId}/users/${userFollowingId}`] = null + updates[`users/${userFollowingId}/circles/-Followers/users/${userId}`] = null firebaseRef.update(updates).then(() => { resolve() @@ -69,7 +69,7 @@ export class CircleService implements ICircleService { return new Promise((resolve,reject) => { let updates: any = {} - updates[`userCircles/${userId}/circles/${circleId}`] = circle + updates[`users/${userId}/circles/${circleId}`] = circle firebaseRef.update(updates).then(() => { resolve() }) @@ -85,7 +85,7 @@ export class CircleService implements ICircleService { return new Promise((resolve,reject) => { let updates: any = {} - updates[`userCircles/${userId}/circles/${circleId}`] = null + updates[`users/${userId}/circles/${circleId}`] = null firebaseRef.update(updates).then(() => { resolve() }) @@ -97,7 +97,7 @@ export class CircleService implements ICircleService { } public getCircles: (userId: string) => Promise<{ [circleId: string]: Circle }> = (userId) => { return new Promise<{ [circleId: string]: Circle }>((resolve,reject) => { - let circlesRef: any = firebaseRef.child(`userCircles/${userId}/circles`) + let circlesRef: any = firebaseRef.child(`users/${userId}/circles`) circlesRef.once('value').then((snapshot: any) => { let circles: any = snapshot.val() || {} diff --git a/src/data/firebaseClient/services/comments/CommentService.ts b/src/data/firebaseClient/services/comments/CommentService.ts index 64a8a19..5be106f 100644 --- a/src/data/firebaseClient/services/comments/CommentService.ts +++ b/src/data/firebaseClient/services/comments/CommentService.ts @@ -35,12 +35,12 @@ export class CommentService implements ICommentService { }) } - public updateComment: (userId: string, postId: string, comment: Comment) - => Promise = (userId, postId, comment) => { + public updateComment: (commentId: string, postId: string, comment: Comment) + => Promise = (commentId, postId, comment) => { return new Promise((resolve,reject) => { let updates: any = {} - updates[`postComments/${postId}/${userId}`] = comment + updates[`postComments/${postId}/${commentId}`] = comment firebaseRef.update(updates) .then(() => { resolve() diff --git a/src/styles/app.scss b/src/styles/app.scss index 6269a1a..72a4735 100644 --- a/src/styles/app.scss +++ b/src/styles/app.scss @@ -1,8 +1,7 @@ @import "base/variables"; @import 'base/grid'; @import 'base/animate'; - - +@import 'base/icon'; // Component styles @import 'components/global'; @import 'components/master'; @@ -19,5 +18,4 @@ @import 'components/login'; @import 'components/signup'; @import 'components/masterLoading'; -@import 'components/settings'; - +@import 'components/settings'; \ No newline at end of file diff --git a/src/styles/base/_animate.scss b/src/styles/base/_animate.scss index aa1a982..53d67d8 100644 --- a/src/styles/base/_animate.scss +++ b/src/styles/base/_animate.scss @@ -165,3 +165,32 @@ } } +.animated { + animation-duration: .5s; + animation-fill-mode: both; +} + +.animated.infinite { + animation-iteration-count: infinite; +} + +.animated.hinge { + animation-duration: 2s; +} + +@keyframes zoomOutUp { + 40% { + opacity: 1; + transform: scale3d(1, 1, 1) translate3d(0, 0px, 0); + animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); + } + to { + transform: scale3d(.8, .8, .8) translate3d(-80px, -40px, 0); + transform-origin: center bottom; + animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); + } +} + +.zoomOutLCorner { + animation-name: zoomOutUp; +} \ No newline at end of file diff --git a/src/styles/base/_icon.scss b/src/styles/base/_icon.scss new file mode 100644 index 0000000..9895dd5 --- /dev/null +++ b/src/styles/base/_icon.scss @@ -0,0 +1,38 @@ +// https://codepen.io/noahblon/pen/xGbXdV +@function _buildIcon($icon) { + $icon: '%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2224%22%20height%3D%2224%22%3E#{$icon}%3C%2Fsvg%3E'; + @return $icon; +} + +@function _buildPath($path, $parameters) { + $icon: '%3Cpath%20fill%3D%22#{map-get($parameters, color)}%22%20stroke%3D%22#{map-get($parameters, stroke-color)}%22%20stroke-width%3D%22#{map-get($parameters, stroke-width)}%22%20style%3D%22#{map-get($parameters, css)}%22%20d%3D%22#{$path}%22%20%2F%3E'; + @return $icon; +} + +@function icon( $icon-name, $color, $stroke-color: transparent, $stroke-width: 0, $css: '' // arbitrary css +) { + $parameters: ( 'color': $color, 'stroke-color': $stroke-color, 'stroke-width': $stroke-width, 'css': $css); + $icons: ( github: _buildPath('M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12', $parameters), google: _buildPath('M7.635 10.909v2.619h4.335c-.173 1.125-1.31 3.295-4.331 3.295-2.604 0-4.731-2.16-4.731-4.823 0-2.662 2.122-4.822 4.728-4.822 1.485 0 2.479.633 3.045 1.178l2.073-1.994c-1.33-1.245-3.056-1.995-5.115-1.995C3.412 4.365 0 7.785 0 12s3.414 7.635 7.635 7.635c4.41 0 7.332-3.098 7.332-7.461 0-.501-.054-.885-.12-1.265H7.635zm16.365 0h-2.183V8.726h-2.183v2.183h-2.182v2.181h2.184v2.184h2.189V13.09H24', $parameters), facebook: _buildPath('M22.676 0H1.324C.593 0 0 .593 0 1.324v21.352C0 23.408.593 24 1.324 24h11.494v-9.294H9.689v-3.621h3.129V8.41c0-3.099 1.894-4.785 4.659-4.785 1.325 0 2.464.097 2.796.141v3.24h-1.921c-1.5 0-1.792.721-1.792 1.771v2.311h3.584l-.465 3.63H16.56V24h6.115c.733 0 1.325-.592 1.325-1.324V1.324C24 .593 23.408 0 22.676 0', $parameters)); + $icon: _buildIcon(map-get($icons, $icon-name)); + @return url("data:image/svg+xml;charset=utf8,#{$icon}"); +} + +.icon { + width: 24px; + height: 24px; + display: inline-block; +} + +.icon-github { + background-image: icon(github, #24292e); +} + +.icon-google { + background-image: icon(google, #db4437); +} + +.icon-fb { + background-image: icon(facebook, #4267b2); +} + +// .icon-dashstroke { background-image: icon(heart, red, black, 2, 'stroke-dasharray : 2px, 1px;'); } \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index c28dd0e..9c3e027 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,147 +7,146 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development'; console.log(process.env.NODE_ENV); try { - envFile(path.join(__dirname, 'config/' + process.env.NODE_ENV + '.env')); + envFile(path.join(__dirname, 'config/' + process.env.NODE_ENV + '.env')); } catch (e) { } var babelOptions = { - plugins: ['transform-decorators-legacy'], - presets: ['babel-polyfill','react', 'env', 'stage-0'] + plugins: ['transform-decorators-legacy'], + presets: ['babel-polyfill', 'react', 'env', 'stage-0'] }; module.exports = { - entry: [ - './src/index.tsx' - ], - externals: { - jquery: 'jQuery' - }, - plugins: (process.env.NODE_ENV === 'production') ? [ - new webpack.optimize.UglifyJsPlugin({ - minimize: true, - compressor: { - warnings: false - } - }), - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify(process.env.NODE_ENV), - API_KEY: JSON.stringify(process.env.API_KEY), - AUTH_DOMAIN: JSON.stringify(process.env.AUTH_DOMAIN), - DATABASE_URL: JSON.stringify(process.env.DATABASE_URL), - STORAGE_BUCKET: JSON.stringify(process.env.STORAGE_BUCKET), - PROJECT_ID: JSON.stringify(process.env.PROJECT_ID), - MESSAGING_SENDER_ID: JSON.stringify(process.env.MESSAGING_SENDER_ID), - HOST_URL: JSON.stringify(process.env.HOST_URL) - } - }) - ] : [ - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify(process.env.NODE_ENV), - API_KEY: JSON.stringify(process.env.API_KEY), - AUTH_DOMAIN: JSON.stringify(process.env.AUTH_DOMAIN), - DATABASE_URL: JSON.stringify(process.env.DATABASE_URL), - STORAGE_BUCKET: JSON.stringify(process.env.STORAGE_BUCKET), - PROJECT_ID: JSON.stringify(process.env.PROJECT_ID), - MESSAGING_SENDER_ID: JSON.stringify(process.env.MESSAGING_SENDER_ID), - HOST_URL: JSON.stringify(process.env.HOST_URL) - } - })], - output: { - path: path.resolve(__dirname, './public'), - filename: 'bundle.js', - - }, - resolve: { - - modules: [ - __dirname, - path.resolve(__dirname, 'node_modules') + entry: [ + './src/index.tsx' ], - alias: { - src: 'src', - components: 'src/components', - reducers: 'src/reducers', - constants: 'src/constants', - core: 'src/core', - data: 'src/data', - api: 'src/api', - layouts: 'src/layouts', - models: 'src/models', - store: 'src/store', - applicationStyles: 'src/styles/app.scss', - actions: 'src/actions', - actionTypes: 'src/constants/actionTypes.jsx' + externals: { + jquery: 'jQuery' + }, + plugins: (process.env.NODE_ENV === 'production') ? [ + new webpack.optimize.UglifyJsPlugin({ + minimize: true, + compressor: { + warnings: false + } + }), + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: JSON.stringify(process.env.NODE_ENV), + API_KEY: JSON.stringify(process.env.API_KEY), + AUTH_DOMAIN: JSON.stringify(process.env.AUTH_DOMAIN), + DATABASE_URL: JSON.stringify(process.env.DATABASE_URL), + STORAGE_BUCKET: JSON.stringify(process.env.STORAGE_BUCKET), + PROJECT_ID: JSON.stringify(process.env.PROJECT_ID), + MESSAGING_SENDER_ID: JSON.stringify(process.env.MESSAGING_SENDER_ID), + HOST_URL: JSON.stringify(process.env.HOST_URL) + } + }) + ] : [ + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: JSON.stringify(process.env.NODE_ENV), + API_KEY: JSON.stringify(process.env.API_KEY), + AUTH_DOMAIN: JSON.stringify(process.env.AUTH_DOMAIN), + DATABASE_URL: JSON.stringify(process.env.DATABASE_URL), + STORAGE_BUCKET: JSON.stringify(process.env.STORAGE_BUCKET), + PROJECT_ID: JSON.stringify(process.env.PROJECT_ID), + MESSAGING_SENDER_ID: JSON.stringify(process.env.MESSAGING_SENDER_ID), + HOST_URL: JSON.stringify(process.env.HOST_URL) + } + }) + ], + output: { + path: path.resolve(__dirname, './public'), + filename: 'bundle-v0.1.js', }, - extensions: [' ', '.scss', ".ts", ".tsx", ".js", ".json", '.jsx'] - }, - module: { - rules: [ - { - test: /\.ts(x?)$/, - exclude: /node_modules/, - use: [ - { - loader: 'babel-loader', - options: babelOptions - }, - { - loader: 'ts-loader', - options: { transpileOnly: true } - } + resolve: { + + modules: [ + __dirname, + path.resolve(__dirname, 'node_modules') + ], + alias: { + src: 'src', + components: 'src/components', + reducers: 'src/reducers', + constants: 'src/constants', + core: 'src/core', + data: 'src/data', + api: 'src/api', + layouts: 'src/layouts', + models: 'src/models', + store: 'src/store', + applicationStyles: 'src/styles/app.scss', + actions: 'src/actions', + actionTypes: 'src/constants/actionTypes.jsx' + + }, + extensions: [' ', '.scss', ".ts", ".tsx", ".js", '.jsx'] + }, + module: { + rules: [{ + test: /\.ts(x?)$/, + exclude: /node_modules/, + use: [{ + loader: 'babel-loader', + options: babelOptions + }, + { + loader: 'ts-loader', + options: { transpileOnly: true } + } + ] + }, + { + enforce: "pre", + test: /\.js$/, + loader: "source-map-loader" + }, + { + test: /\.js(x?)$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader', + options: babelOptions + } + }, + { + test: /\.scss$/, + use: [{ + loader: "style-loader" + }, { + loader: "css-loader" + }, { + loader: "sass-loader", + options: { + includePaths: [ + + ] + } + }] + }, + { + test: /\.css$/, + use: [{ + loader: "style-loader" + }, { + loader: "css-loader" + + }] + }, + { + test: /\.(woff|woff2|eot|ttf|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, + loader: 'url-loader' + }, { + test: /\.(jpe?g|png|webp|gif|cur)$/, + loader: 'file-loader?name=/images/[name].[ext]' + } + + ] - }, - { - enforce: "pre", - test: /\.js$/, - loader: "source-map-loader" - }, - { - test: /\.js(x?)$/, - exclude: /(node_modules|bower_components)/, - use: { - loader: 'babel-loader', - options: babelOptions - } - }, - { - test: /\.scss$/, - use: [{ - loader: "style-loader" - }, { - loader: "css-loader" - }, { - loader: "sass-loader", - options: { - includePaths: [ - - ] - } - }] - }, - { - test: /\.css$/, - use: [{ - loader: "style-loader" - }, { - loader: "css-loader" - - }] - }, - { - test: /\.(woff|woff2|eot|ttf|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, - loader: 'url-loader' - }, { - test: /\.(jpe?g|png|webp|gif|cur)$/, - loader: 'file-loader?name=/images/[name].[ext]' - } - - - ] - }, - devtool: process.env.NODE_ENV === 'production' ? undefined : 'cheap-module-eval-source-map' -}; + }, + devtool: process.env.NODE_ENV === 'production' ? undefined : 'cheap-module-eval-source-map' +}; \ No newline at end of file