[Feature Request] User account confirmation (#23)
This commit is contained in:
5
.firebaserc
Normal file
5
.firebaserc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"projects": {
|
||||
"default": "love-social"
|
||||
}
|
||||
}
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,5 +4,4 @@ config/
|
||||
.vscode/
|
||||
src/data/awsClient
|
||||
src/components/AWS.tsx
|
||||
.firebaserc
|
||||
firebase.json
|
||||
npm-debug.log
|
||||
9
firebase.json
Normal file
9
firebase.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"hosting": {
|
||||
"public": "public",
|
||||
"rewrites": [{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ export const dbLogin = (email: string, password: string) => {
|
||||
dispatch(globalActions.showNotificationRequest())
|
||||
return authorizeService.login(email, password).then((result) => {
|
||||
dispatch(globalActions.showNotificationSuccess())
|
||||
dispatch(login(result.uid))
|
||||
dispatch(login(result.uid,result.emailVerified))
|
||||
dispatch(push('/'))
|
||||
}, (error: SocialError) => dispatch(globalActions.showErrorMessage(error.code)))
|
||||
}
|
||||
@@ -71,7 +71,8 @@ export const dbSignup = (user: UserRegisterModel) => {
|
||||
userId: result.uid,
|
||||
...user
|
||||
}))
|
||||
dispatch(push('/'))
|
||||
dispatch(dbSendEmailVerfication())
|
||||
dispatch(push('/emailVerification'))
|
||||
})
|
||||
.catch((error: SocialError) => dispatch(globalActions.showErrorMessage(error.code)))
|
||||
}
|
||||
@@ -129,16 +130,36 @@ export const dbResetPassword = (email: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send email verification
|
||||
*/
|
||||
export const dbSendEmailVerfication = () => {
|
||||
return (dispatch: any, getState: any) => {
|
||||
dispatch(globalActions.showNotificationRequest())
|
||||
|
||||
return authorizeService.sendEmailVerification().then(() => {
|
||||
// Send email verification successful.
|
||||
dispatch(globalActions.showNotificationSuccess())
|
||||
dispatch(push('/'))
|
||||
})
|
||||
.catch((error: SocialError) => {
|
||||
// An error happened.
|
||||
dispatch(globalActions.showErrorMessage(error.code))
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/* _____________ CRUD State _____________ */
|
||||
|
||||
/**
|
||||
* Loing user
|
||||
* @param {string} uids
|
||||
*/
|
||||
export const login = (uid: string) => {
|
||||
export const login = (uid: string, isVerifide: boolean) => {
|
||||
return {
|
||||
type: AuthorizeActionType.LOGIN,
|
||||
payload: { authed: true, uid }
|
||||
payload: { authed: true, isVerifide, uid }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
132
src/components/emailVerification/EmailVerificationComponent.tsx
Normal file
132
src/components/emailVerification/EmailVerificationComponent.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
// - 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 { IEmailVerificationComponentProps } from './IEmailVerificationComponentProps'
|
||||
import { IEmailVerificationComponentState } from './IEmailVerificationComponentState'
|
||||
|
||||
/**
|
||||
* Create component class
|
||||
*
|
||||
* @export
|
||||
* @class EmailVerificationComponent
|
||||
* @extends {Component}
|
||||
*/
|
||||
export class EmailVerificationComponent extends Component<IEmailVerificationComponentProps,IEmailVerificationComponentState> {
|
||||
|
||||
styles = {
|
||||
message: {
|
||||
fontWeight: 100
|
||||
},
|
||||
sendButton: {
|
||||
marginTop: 60
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component constructor
|
||||
* @param {object} props is an object properties of component
|
||||
*/
|
||||
constructor (props: IEmailVerificationComponentProps) {
|
||||
super(props)
|
||||
|
||||
// Binding function to `this`
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (
|
||||
<div>
|
||||
|
||||
<h1 style={{
|
||||
textAlign: 'center',
|
||||
padding: '20px',
|
||||
fontSize: '30px',
|
||||
fontWeight: 500,
|
||||
lineHeight: '32px',
|
||||
margin: 'auto',
|
||||
color: 'rgba(138, 148, 138, 0.2)'
|
||||
}}>Green</h1>
|
||||
|
||||
<div className='animate-bottom'>
|
||||
<Paper style={paperStyle} zDepth={1} rounded={false} >
|
||||
<div style={{ padding: '48px 40px 36px' }}>
|
||||
<div style={{
|
||||
paddingLeft: '40px',
|
||||
paddingRight: '40px'
|
||||
}}>
|
||||
|
||||
<h2 style={{
|
||||
textAlign: 'left',
|
||||
paddingTop: '16px',
|
||||
fontSize: '24px',
|
||||
fontWeight: 400,
|
||||
lineHeight: '32px',
|
||||
margin: 0
|
||||
}} className='zoomOutLCorner animated'>Email Verification</h2>
|
||||
</div>
|
||||
<p style={this.styles.message as any}>
|
||||
An verificiation email has been already sent to you. Please check your inbox. If you couldn't see the emai, please resend email verification.
|
||||
</p>
|
||||
<div style={this.styles.sendButton}>
|
||||
<RaisedButton label='Send Email Verification' primary={true} onClick={() => this.props.sendEmailVerification()} />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</Paper>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: IEmailVerificationComponentProps) => {
|
||||
return {
|
||||
loginPage: () => {
|
||||
dispatch(push('/login'))
|
||||
},
|
||||
sendEmailVerification: () => dispatch(authorizeActions.dbSendEmailVerfication())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: IEmailVerificationComponentProps) => {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// - Connect component to redux store
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(EmailVerificationComponent as any))
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface IEmailVerificationComponentProps {
|
||||
|
||||
sendEmailVerification: () => any
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
export interface IEmailVerificationComponentState {
|
||||
|
||||
|
||||
}
|
||||
2
src/components/emailVerification/index.ts
Normal file
2
src/components/emailVerification/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import EmailVerificationComponent from './EmailVerificationComponent'
|
||||
export default EmailVerificationComponent
|
||||
@@ -28,7 +28,18 @@ import People from 'components/people'
|
||||
import CircleAPI from 'api/CircleAPI'
|
||||
|
||||
// - Import actions
|
||||
import * as globalActions from 'actions/globalActions'
|
||||
// - Import actions
|
||||
import {
|
||||
authorizeActions,
|
||||
imageGalleryActions,
|
||||
postActions,
|
||||
commentActions,
|
||||
voteActions,
|
||||
userActions,
|
||||
globalActions,
|
||||
circleActions,
|
||||
notifyActions
|
||||
} from 'actions'
|
||||
|
||||
import { IHomeComponentProps } from './IHomeComponentProps'
|
||||
import { IHomeComponentState } from './IHomeComponentState'
|
||||
@@ -93,6 +104,24 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
})
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
|
||||
const {global, clearData, loadData, authed, defaultDataEnable, isVerifide, goTo } = this.props
|
||||
if (!authed) {
|
||||
goTo!('/login')
|
||||
return
|
||||
}
|
||||
if (!isVerifide) {
|
||||
goTo!('/emailVerification')
|
||||
|
||||
} else if (!global.defaultLoadDataStatus) {
|
||||
|
||||
clearData!()
|
||||
loadData!()
|
||||
defaultDataEnable!()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render DOM component
|
||||
*
|
||||
@@ -101,7 +130,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
* @memberof Home
|
||||
*/
|
||||
render () {
|
||||
|
||||
const {loaded} = this.props
|
||||
return (
|
||||
<div id='home'>
|
||||
<HomeHeader sidebar={this.state.sidebarOpen} sidebarStatus={this.state.sidebarStatus} />
|
||||
@@ -123,7 +152,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarMain>
|
||||
<Switch>
|
||||
{loaded ? (<Switch>
|
||||
<Route path='/people/:tab?' render={() => {
|
||||
return (
|
||||
this.props.authed
|
||||
@@ -150,7 +179,8 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
: <Redirect to='/login' />
|
||||
)
|
||||
}} />
|
||||
</Switch>
|
||||
</Switch>)
|
||||
: ''}
|
||||
</SidebarMain>
|
||||
</Sidebar>
|
||||
|
||||
@@ -160,16 +190,40 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
// - Map dispatch to props
|
||||
const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
|
||||
return {
|
||||
|
||||
return {
|
||||
loadData: () => {
|
||||
dispatch(commentActions.dbGetComments())
|
||||
dispatch(imageGalleryActions.dbGetImageGallery())
|
||||
dispatch(postActions.dbGetPosts())
|
||||
dispatch(userActions.dbGetUserInfo())
|
||||
dispatch(voteActions.dbGetVotes())
|
||||
dispatch(notifyActions.dbGetNotifications())
|
||||
dispatch(circleActions.dbGetCircles())
|
||||
|
||||
},
|
||||
clearData: () => {
|
||||
dispatch(imageGalleryActions.clearAllData())
|
||||
dispatch(postActions.clearAllData())
|
||||
dispatch(userActions.clearAllData())
|
||||
dispatch(commentActions.clearAllData())
|
||||
dispatch(voteActions.clearAllvotes())
|
||||
dispatch(notifyActions.clearAllNotifications())
|
||||
dispatch(circleActions.clearAllCircles())
|
||||
dispatch(globalActions.clearTemp())
|
||||
|
||||
},
|
||||
defaultDataDisable: () => {
|
||||
dispatch(globalActions.defaultDataDisable())
|
||||
},
|
||||
defaultDataEnable: () => {
|
||||
dispatch(globalActions.defaultDataEnable())
|
||||
},
|
||||
goTo: (url: string) => dispatch(push(url))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,20 +233,24 @@ const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IHomeComponentProps) => {
|
||||
const { uid } = state.authorize
|
||||
const { authorize, global, user, post, comment, imageGallery, vote, notify, circle } = state
|
||||
const { uid } = authorize
|
||||
let mergedPosts = {}
|
||||
const circles = state.circle ? (state.circle.userCircles[uid] || {}) : {}
|
||||
const circles = circle ? (circle.userCircles[uid] || {}) : {}
|
||||
const followingUsers = CircleAPI.getFollowingUsers(circles)
|
||||
const posts = state.post.userPosts ? state.post.userPosts[state.authorize.uid] : {}
|
||||
const posts = post.userPosts ? post.userPosts[authorize.uid] : {}
|
||||
Object.keys(followingUsers).forEach((userId) => {
|
||||
let newPosts = state.post.userPosts ? state.post.userPosts[userId] : {}
|
||||
let newPosts = post.userPosts ? post.userPosts[userId] : {}
|
||||
_.merge(mergedPosts,newPosts)
|
||||
})
|
||||
_.merge(mergedPosts,posts)
|
||||
return {
|
||||
authed: state.authorize.authed,
|
||||
mainStyle: state.global.sidebarMainStyle,
|
||||
mergedPosts
|
||||
authed: authorize.authed,
|
||||
isVerifide: authorize.isVerifide,
|
||||
mainStyle: global.sidebarMainStyle,
|
||||
mergedPosts,
|
||||
global,
|
||||
loaded: user.loaded && post.loaded && comment.loaded && imageGallery.loaded && vote.loaded && notify.loaded && circle.loaded
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,14 @@ export interface IHomeComponentProps {
|
||||
*/
|
||||
authed?: boolean
|
||||
|
||||
/**
|
||||
* If user email is verifide {true} or not {false}
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof IHomeComponentProps
|
||||
*/
|
||||
isVerifide?: boolean
|
||||
|
||||
/**
|
||||
* User identifier
|
||||
*
|
||||
@@ -25,4 +33,59 @@ export interface IHomeComponentProps {
|
||||
* @memberof IHomeComponentProps
|
||||
*/
|
||||
mergedPosts?: {[postId: string]: Post}
|
||||
|
||||
/**
|
||||
* Global state
|
||||
*
|
||||
* @type {*}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
global?: any
|
||||
|
||||
/**
|
||||
* Clear user date from store
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
clearData?: Function
|
||||
|
||||
/**
|
||||
* Set flag {true} which all user data has loaded
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
defaultDataEnable?: Function
|
||||
/**
|
||||
* Load user data into store
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
loadData?: Function
|
||||
|
||||
/**
|
||||
* Set flag {false} which user data has not loaded
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
defaultDataDisable?: Function
|
||||
|
||||
/**
|
||||
* Redirect to [url]
|
||||
*
|
||||
* @memberof IHomeComponentProps
|
||||
*/
|
||||
goTo?: (url: string) => any
|
||||
|
||||
/**
|
||||
* If all requierment data loaded {true} or not {false}
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof IHomeComponentProps
|
||||
*/
|
||||
loaded?: boolean
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { User } from 'core/domain/users';
|
||||
export interface IMasterComponentProps {
|
||||
/**
|
||||
* Close gloal message
|
||||
@@ -5,91 +6,91 @@ export interface IMasterComponentProps {
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
closeMessage: Function,
|
||||
closeMessage: Function
|
||||
/**
|
||||
* Show progress bar information
|
||||
*
|
||||
* @type {*}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
progress: any,
|
||||
progress: any
|
||||
/**
|
||||
* Login a user
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
login: Function,
|
||||
login: (userId: string, isVerifide: boolean) => any
|
||||
/**
|
||||
* Global state
|
||||
*
|
||||
* @type {*}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
global: any,
|
||||
global: any
|
||||
/**
|
||||
* Set flag {false} which user data has not loaded
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
defaultDataDisable: Function,
|
||||
defaultDataDisable: Function
|
||||
/**
|
||||
* Logout current user
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
logout: Function,
|
||||
logout: Function
|
||||
/**
|
||||
* Clear user date from store
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
clearData: Function,
|
||||
clearData: Function
|
||||
/**
|
||||
* Prepare default data for a guest user
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
loadDataGuest: Function,
|
||||
loadDataGuest: Function
|
||||
/**
|
||||
* Set flag {true} which all user data has loaded
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
defaultDataEnable: Function,
|
||||
defaultDataEnable: Function
|
||||
/**
|
||||
* Load user data into store
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
loadData: Function,
|
||||
loadData: Function
|
||||
/**
|
||||
* If all data from all entities are loaded {true} if not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
loaded: Boolean,
|
||||
loaded: Boolean
|
||||
/**
|
||||
* If current user is guest {true} if no
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
guest: Boolean,
|
||||
guest: Boolean
|
||||
/**
|
||||
* If current user is authed {true} if not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IMasterProps
|
||||
*/
|
||||
authed: Boolean,
|
||||
authed: Boolean
|
||||
/**
|
||||
* Authed user identifier
|
||||
*
|
||||
|
||||
@@ -21,4 +21,12 @@ export interface IMasterComponentState {
|
||||
* @memberof IMasterState
|
||||
*/
|
||||
dataLoaded: boolean
|
||||
|
||||
/**
|
||||
* If user verifide it's email {true} or not {false}
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof IMasterComponentState
|
||||
*/
|
||||
isVerifide: boolean
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import LinearProgress from 'material-ui/LinearProgress'
|
||||
// - Import components
|
||||
import Home from 'components/home'
|
||||
import Signup from 'components/signup'
|
||||
import EmailVerification from 'components/emailVerification'
|
||||
import Login from 'components/login'
|
||||
import ResetPassword from 'components/resetPassword'
|
||||
import Setting from 'components/setting'
|
||||
@@ -50,7 +51,8 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
|
||||
this.state = {
|
||||
loading: true,
|
||||
authed: false,
|
||||
dataLoaded: false
|
||||
dataLoaded: false,
|
||||
isVerifide: false
|
||||
}
|
||||
|
||||
// Binding functions to `this`
|
||||
@@ -81,28 +83,26 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
|
||||
|
||||
componentWillMount () {
|
||||
|
||||
this._authourizeService.onAuthStateChanged((user: any) => {
|
||||
|
||||
this._authourizeService.onAuthStateChanged((isVerifide: boolean, user: any) => {
|
||||
const {global, clearData, loadDataGuest, defaultDataDisable, defaultDataEnable, login, logout } = this.props
|
||||
if (user) {
|
||||
this.props.login(user)
|
||||
login(user.uid,isVerifide)
|
||||
this.setState({
|
||||
loading: false
|
||||
loading: false,
|
||||
isVerifide: true
|
||||
})
|
||||
if (!this.props.global.defaultLoadDataStatus) {
|
||||
this.props.clearData()
|
||||
this.props.loadData()
|
||||
this.props.defaultDataEnable()
|
||||
}
|
||||
|
||||
} else {
|
||||
this.props.logout()
|
||||
logout()
|
||||
this.setState({
|
||||
loading: false
|
||||
loading: false,
|
||||
isVerifide: false
|
||||
})
|
||||
if (this.props.global.defaultLoadDataStatus) {
|
||||
this.props.defaultDataDisable()
|
||||
this.props.clearData()
|
||||
if (global.defaultLoadDataStatus) {
|
||||
defaultDataDisable()
|
||||
clearData()
|
||||
}
|
||||
this.props.loadDataGuest()
|
||||
loadDataGuest()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -117,7 +117,8 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
|
||||
*/
|
||||
public render (): React.ReactElement<{}> {
|
||||
|
||||
const { progress, global } = this.props
|
||||
const { progress, global, loaded, guest } = this.props
|
||||
const { loading, isVerifide } = this.state
|
||||
|
||||
return (
|
||||
<div id='master'>
|
||||
@@ -128,25 +129,25 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
|
||||
<div className='master__loading animate-fading2' style={{ display: (global.showTopLoading ? 'flex' : 'none') }}>
|
||||
<div className='title'>Loading ... </div>
|
||||
</div>
|
||||
<MasterLoading activeLoading={this.state.loading || !(this.props.loaded || this.props.guest)} handleLoading={this.handleLoading} />
|
||||
<MasterLoading activeLoading={loading} handleLoading={this.handleLoading} />
|
||||
|
||||
{(!this.state.loading && (this.props.loaded || this.props.guest))
|
||||
? (<Switch>
|
||||
<Route path='/signup' component={Signup} />
|
||||
<Route path='/settings' component={Setting} />
|
||||
<Route path='/resetPassword' component={ResetPassword} />
|
||||
<Route path='/login' render={() => {
|
||||
console.log('this.props.authed: ', this.props.authed, 'this.props: ', this.props)
|
||||
return (
|
||||
this.props.authed
|
||||
? <Redirect to='/' />
|
||||
: <Login />
|
||||
)
|
||||
}
|
||||
} />
|
||||
<Route render={() => <Home uid={this.props.uid} />} />
|
||||
{(!loading) ? (<Switch>
|
||||
<Route path='/signup' component={Signup} />
|
||||
<Route path='/emailVerification' component={EmailVerification} />
|
||||
<Route path='/settings' component={Setting} />
|
||||
<Route path='/resetPassword' component={ResetPassword} />
|
||||
<Route path='/login' render={() => {
|
||||
return (
|
||||
this.props.authed
|
||||
? <Redirect to='/' />
|
||||
: <Login />
|
||||
)
|
||||
}
|
||||
} />
|
||||
<Route render={() => <Home uid={this.props.uid} />} />
|
||||
|
||||
</Switch>) : ''
|
||||
</Switch>)
|
||||
: ''
|
||||
}
|
||||
<Snackbar
|
||||
open={this.props.global.messageOpen}
|
||||
@@ -164,16 +165,6 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
|
||||
const mapDispatchToProps = (dispatch: any, ownProps: IMasterComponentProps) => {
|
||||
|
||||
return {
|
||||
loadData: () => {
|
||||
dispatch(commentActions.dbGetComments())
|
||||
dispatch(imageGalleryActions.dbGetImageGallery())
|
||||
dispatch(postActions.dbGetPosts())
|
||||
dispatch(userActions.dbGetUserInfo())
|
||||
dispatch(voteActions.dbGetVotes())
|
||||
dispatch(notifyActions.dbGetNotifications())
|
||||
dispatch(circleActions.dbGetCircles())
|
||||
|
||||
},
|
||||
clearData: () => {
|
||||
dispatch(imageGalleryActions.clearAllData())
|
||||
dispatch(postActions.clearAllData())
|
||||
@@ -185,8 +176,8 @@ const mapDispatchToProps = (dispatch: any, ownProps: IMasterComponentProps) => {
|
||||
dispatch(globalActions.clearTemp())
|
||||
|
||||
},
|
||||
login: (user: any) => {
|
||||
dispatch(authorizeActions.login(user.uid))
|
||||
login: (userId: string, isVerifide: boolean) => {
|
||||
dispatch(authorizeActions.login(userId, isVerifide))
|
||||
},
|
||||
logout: () => {
|
||||
dispatch(authorizeActions.logout())
|
||||
@@ -218,8 +209,7 @@ const mapStateToProps = (state: any) => {
|
||||
uid: authorize.uid,
|
||||
authed: authorize.authed,
|
||||
progress: global.progress,
|
||||
global: global,
|
||||
loaded: user.loaded && post.loaded && comment.loaded && imageGallery.loaded && vote.loaded && notify.loaded && circle.loaded
|
||||
global: global
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
16
src/components/resetPassword/IResetPasswordComponentProps.ts
Normal file
16
src/components/resetPassword/IResetPasswordComponentProps.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export interface IResetPasswordComponentProps {
|
||||
|
||||
/**
|
||||
* Reset password
|
||||
*
|
||||
* @memberof IResetPasswordComponentProps
|
||||
*/
|
||||
resetPassword?: (email: string) => any
|
||||
|
||||
/**
|
||||
* Redirect to login page
|
||||
*
|
||||
* @memberof IResetPasswordComponentProps
|
||||
*/
|
||||
loginPage?: () => void
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
|
||||
export interface IRestPasswordComponentState {
|
||||
export interface IResetPasswordComponentState {
|
||||
|
||||
/**
|
||||
* Email input value
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IRestPasswordComponentState
|
||||
* @memberof IResetPasswordComponentState
|
||||
*/
|
||||
emailInput: string
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface IRestPasswordComponentState {
|
||||
* Email input error text
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IRestPasswordComponentState
|
||||
* @memberof IResetPasswordComponentState
|
||||
*/
|
||||
emailInputError: string
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
export interface IRestPasswordComponentProps {
|
||||
|
||||
/**
|
||||
* Reset password
|
||||
*
|
||||
* @memberof IRestPasswordComponentProps
|
||||
*/
|
||||
resetPassword: (email: string) => any
|
||||
|
||||
/**
|
||||
* Redirect to login page
|
||||
*
|
||||
* @memberof IRestPasswordComponentProps
|
||||
*/
|
||||
loginPage: () => void
|
||||
}
|
||||
@@ -11,23 +11,23 @@ import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
||||
|
||||
// - Import actions
|
||||
import * as authorizeActions from 'actions/authorizeActions'
|
||||
import { IRestPasswordComponentProps } from './IRestPasswordComponentProps'
|
||||
import { IRestPasswordComponentState } from './IRestPasswordComponentState'
|
||||
import { IResetPasswordComponentProps } from './IResetPasswordComponentProps'
|
||||
import { IResetPasswordComponentState } from './IResetPasswordComponentState'
|
||||
|
||||
/**
|
||||
* Create component class
|
||||
*
|
||||
* @export
|
||||
* @class RestPasswordComponent
|
||||
* @class ResetPasswordComponent
|
||||
* @extends {Component}
|
||||
*/
|
||||
export class RestPasswordComponent extends Component<IRestPasswordComponentProps,IRestPasswordComponentState> {
|
||||
export class ResetPasswordComponent extends Component<IResetPasswordComponentProps,IResetPasswordComponentState> {
|
||||
|
||||
/**
|
||||
* Component constructor
|
||||
* @param {object} props is an object properties of component
|
||||
*/
|
||||
constructor (props: IRestPasswordComponentProps) {
|
||||
constructor (props: IResetPasswordComponentProps) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -68,7 +68,7 @@ export class RestPasswordComponent extends Component<IRestPasswordComponentProps
|
||||
return
|
||||
}
|
||||
|
||||
this.props.resetPassword(this.state.emailInput)
|
||||
this.props.resetPassword!(this.state.emailInput)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +148,7 @@ export class RestPasswordComponent extends Component<IRestPasswordComponentProps
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapDispatchToProps = (dispatch: Function, ownProps: IRestPasswordComponentProps) => {
|
||||
const mapDispatchToProps = (dispatch: Function, ownProps: IResetPasswordComponentProps) => {
|
||||
return {
|
||||
loginPage: () => {
|
||||
dispatch(push('/login'))
|
||||
@@ -163,11 +163,11 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IRestPasswordComponent
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IRestPasswordComponentProps) => {
|
||||
const mapStateToProps = (state: any, ownProps: IResetPasswordComponentProps) => {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// - Connect component to redux store
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(RestPasswordComponent as any))
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(ResetPasswordComponent as any))
|
||||
@@ -1,2 +1,2 @@
|
||||
import RestPasswordComponent from './RestPasswordComponent'
|
||||
export default RestPasswordComponent
|
||||
import ResetPasswordComponent from './ResetPasswordComponent'
|
||||
export default ResetPasswordComponent
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
import { BaseDomain } from 'core/domain/common'
|
||||
|
||||
export class LoginUser extends BaseDomain{
|
||||
export class LoginUser extends BaseDomain {
|
||||
|
||||
constructor(uid: string){
|
||||
super()
|
||||
constructor (private _uid: string, private _emailVerified: boolean) {
|
||||
super()
|
||||
}
|
||||
|
||||
this._uid = uid
|
||||
}
|
||||
|
||||
/**
|
||||
* User identifier
|
||||
*
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof LoginUser
|
||||
*/
|
||||
|
||||
private _uid : string
|
||||
public get uid() : string {
|
||||
return this._uid
|
||||
}
|
||||
public get uid (): string {
|
||||
return this._uid
|
||||
}
|
||||
|
||||
|
||||
public get emailVerified (): boolean {
|
||||
return this._emailVerified
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
export class SocialError {
|
||||
export class SocialError extends Error {
|
||||
private _isError: Boolean
|
||||
|
||||
constructor (private _code: string, private _message: string) {
|
||||
super(_message)
|
||||
this._isError = true
|
||||
}
|
||||
/**
|
||||
* Error code
|
||||
*
|
||||
@@ -26,13 +32,8 @@ export class SocialError {
|
||||
* @memberof SocialError
|
||||
*/
|
||||
|
||||
private _isError: Boolean
|
||||
public get isError (): Boolean {
|
||||
return this._isError
|
||||
}
|
||||
|
||||
constructor (private _code: string, private _message: string) {
|
||||
this._isError = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export interface IAuthorizeService {
|
||||
*
|
||||
* @memberof IAuthorizeService
|
||||
*/
|
||||
onAuthStateChanged: (callBack: (user: User) => void) => void
|
||||
onAuthStateChanged: (callBack: (isVerifide: boolean, user: User) => void) => void
|
||||
|
||||
/**
|
||||
* Reset user password
|
||||
@@ -48,4 +48,11 @@ export interface IAuthorizeService {
|
||||
* @memberof IAuthorizeService
|
||||
*/
|
||||
resetPassword: (email: string) => Promise<void>
|
||||
|
||||
/**
|
||||
* Send email verification
|
||||
*
|
||||
* @memberof IAuthorizeService
|
||||
*/
|
||||
sendEmailVerification: () => Promise<void>
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export class AuthorizeService implements IAuthorizeService {
|
||||
firebaseAuth()
|
||||
.signInWithEmailAndPassword(email, password)
|
||||
.then((result) => {
|
||||
resolve(new LoginUser(result.uid))
|
||||
resolve(new LoginUser(result.uid, result.emailVerified))
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(new SocialError(error.code, error.message))
|
||||
@@ -108,8 +108,18 @@ export class AuthorizeService implements IAuthorizeService {
|
||||
*
|
||||
* @memberof IAuthorizeService
|
||||
*/
|
||||
public onAuthStateChanged: (callBack: (user: User) => void) => any = (callBack) => {
|
||||
firebaseAuth().onAuthStateChanged(callBack)
|
||||
public onAuthStateChanged: (callBack: (isVerifide: boolean, user: User) => void) => any = (callBack) => {
|
||||
firebaseAuth().onAuthStateChanged( (user: any) => {
|
||||
let isVerifide = false
|
||||
if (user) {
|
||||
if (user.emailVerified) {
|
||||
isVerifide = true
|
||||
} else {
|
||||
isVerifide = false
|
||||
}
|
||||
}
|
||||
callBack(isVerifide,user)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,4 +139,23 @@ export class AuthorizeService implements IAuthorizeService {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public sendEmailVerification: () => Promise<void> = () => {
|
||||
return new Promise<void>((resolve,reject) => {
|
||||
let auth = firebaseAuth()
|
||||
const user = auth.currentUser
|
||||
|
||||
if (user) {
|
||||
user.sendEmailVerification().then(() => {
|
||||
resolve()
|
||||
}).catch((error: any) => {
|
||||
// An error happened.
|
||||
reject(new SocialError(error.code, error.message))
|
||||
})
|
||||
} else {
|
||||
reject(new SocialError('nullException', 'User was null'));
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,48 @@
|
||||
/**
|
||||
* Post state
|
||||
*
|
||||
* Post state
|
||||
*
|
||||
* @export
|
||||
* @class AuthorizeState
|
||||
*/
|
||||
export class AuthorizeState {
|
||||
export class AuthorizeState {
|
||||
|
||||
/**
|
||||
* Authorized user identifier
|
||||
*
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof AuthorizeState
|
||||
*/
|
||||
uid: number = 0
|
||||
uid: number = 0
|
||||
|
||||
/**
|
||||
* If user is authed {true} or not {false}
|
||||
*
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof AuthorizeState
|
||||
*/
|
||||
authed: Boolean = false
|
||||
authed: Boolean = false
|
||||
|
||||
/**
|
||||
* If user is verifide {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof AuthorizeState
|
||||
*/
|
||||
isVerfide: Boolean = false
|
||||
|
||||
/**
|
||||
* If user password is updated {true} or not {false}
|
||||
*
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof AuthorizeState
|
||||
*/
|
||||
updatePassword: Boolean = false
|
||||
updatePassword: Boolean = false
|
||||
|
||||
/**
|
||||
* If the user is guest {true} or not {false}
|
||||
*
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof AuthorizeState
|
||||
*/
|
||||
guest: Boolean = false
|
||||
}
|
||||
guest: Boolean = false
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
// - Import action types
|
||||
import {AuthorizeActionType} from 'constants/authorizeActionType'
|
||||
|
||||
import { AuthorizeActionType } from 'constants/authorizeActionType'
|
||||
|
||||
/**
|
||||
* Authorize action interface
|
||||
*
|
||||
*
|
||||
* @export
|
||||
* @interface IAuthorizeAction
|
||||
*/
|
||||
export interface IAuthorizeAction {
|
||||
payload: any
|
||||
type: AuthorizeActionType
|
||||
|
||||
}
|
||||
export interface IAuthorizeAction {
|
||||
payload: any
|
||||
type: AuthorizeActionType
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ export let authorizeReducer = (state: AuthorizeState = new AuthorizeState(), act
|
||||
...state,
|
||||
uid: payload.uid,
|
||||
authed: true,
|
||||
guest: false
|
||||
guest: false,
|
||||
isVerifide: payload.isVerifide
|
||||
}
|
||||
case AuthorizeActionType.LOGOUT:
|
||||
return{
|
||||
|
||||
@@ -6,101 +6,101 @@
|
||||
*/
|
||||
export class GlobalState {
|
||||
|
||||
/**
|
||||
* Set percent of loading progress and visibility for Master component
|
||||
*
|
||||
* @type {{
|
||||
* percent: number,
|
||||
* visible: Boolean
|
||||
* }}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* Set percent of loading progress and visibility for Master component
|
||||
*
|
||||
* @type {{
|
||||
* percent: number,
|
||||
* visible: Boolean
|
||||
* }}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
progress: {
|
||||
percent: number
|
||||
visible: Boolean
|
||||
} = {
|
||||
percent : 0,
|
||||
visible : false
|
||||
percent: 0,
|
||||
visible: false
|
||||
}
|
||||
|
||||
/**
|
||||
* If loading is enabled {true} or not false
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* If loading is enabled {true} or not false
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
loadingStatus: Boolean = true
|
||||
|
||||
/**
|
||||
* If user date is loaded {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* If user date is loaded {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
defaultLoadDataStatus: Boolean = false
|
||||
|
||||
/**
|
||||
* If message popup is open {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* If message popup is open {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
messageOpen: Boolean = false
|
||||
|
||||
/**
|
||||
* The text of popup global message
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* The text of popup global message
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
message: string = ''
|
||||
|
||||
/**
|
||||
* Window size
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* Window size
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
windowWidth: number = 0
|
||||
|
||||
/**
|
||||
* Window height
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* Window height
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
windowHeight: number = 0
|
||||
|
||||
/**
|
||||
* The text of website header
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* The text of website header
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
headerTitle: string = ''
|
||||
|
||||
/**
|
||||
* Top loading is visible {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* Top loading is visible {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
showTopLoading: Boolean = false
|
||||
|
||||
/**
|
||||
* Top loading message queue
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* Top loading message queue
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
topLoadingQueue: number = 0
|
||||
|
||||
/**
|
||||
* Temp date storage
|
||||
*
|
||||
* @type {*}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
/**
|
||||
* Temp date storage
|
||||
*
|
||||
* @type {*}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
temp: any = {
|
||||
caller: []
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user