[Enhancement] Apply immutable js. (#49)
This commit is contained in:
11
package.json
11
package.json
@@ -18,9 +18,11 @@
|
||||
"author": "Amir Movahedi",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react-helmet": "^5.0.5",
|
||||
"@types/redux-devtools": "^3.0.43",
|
||||
"@types/redux-devtools-dock-monitor": "^1.1.32",
|
||||
"@types/redux-devtools-log-monitor": "^1.0.33",
|
||||
"@types/redux-immutable": "^3.0.38",
|
||||
"amazon-cognito-identity-js": "^1.21.0",
|
||||
"aws-sdk": "^2.132.0",
|
||||
"axios": "^0.16.2",
|
||||
@@ -29,6 +31,7 @@
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"faker": "^4.1.0",
|
||||
"firebase": "^4.11.0",
|
||||
"immutable": "^3.8.2",
|
||||
"install": "^0.10.2",
|
||||
"inversify": "^4.6.0",
|
||||
"jss-rtl": "^0.2.1",
|
||||
@@ -48,9 +51,11 @@
|
||||
"react-day-picker": "^7.0.7",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-event-listener": "^0.5.1",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-infinite-scroller": "^1.1.2",
|
||||
"react-linkify": "^0.2.1",
|
||||
"react-localize-redux": "^2.15.1",
|
||||
"react-loadable": "^5.3.1",
|
||||
"react-localize-redux": "^2.16.0",
|
||||
"react-parallax": "^1.6.1",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-router": "^4.1.1 ",
|
||||
@@ -62,10 +67,12 @@
|
||||
"react-tap-event-plugin": "^3.0.2",
|
||||
"redux": "^3.7.2",
|
||||
"redux-actions": "^2.0.3",
|
||||
"redux-saga": "^0.16.0",
|
||||
"redux-devtools": "^3.4.1",
|
||||
"redux-devtools-dock-monitor": "^1.1.3",
|
||||
"redux-devtools-extension": "^2.13.2",
|
||||
"redux-devtools-log-monitor": "^1.4.0",
|
||||
"redux-immutable": "^4.0.0",
|
||||
"redux-saga": "^0.16.0",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"reflect-metadata": "^0.1.10",
|
||||
"save": "^2.3.0",
|
||||
|
||||
@@ -24,7 +24,8 @@ const sortCommentsByDate = (sortedObjects: comments) => {
|
||||
return _.fromPairs(_.toPairs(sortedObjects)
|
||||
.sort((a: any, b: any) => parseInt(b[1].creationDate, 10) - parseInt(a[1].creationDate, 10)).slice(0, 3))
|
||||
|
||||
}
|
||||
}
|
||||
return sortedObjects
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -4,11 +4,14 @@ import * as moment from 'moment/moment'
|
||||
* @param title log title
|
||||
* @param data log data object
|
||||
*/
|
||||
const logger = (title: string, data: any) => {
|
||||
const logger = (title: string, ...data: any[]) => {
|
||||
const randomColor = getRandomColor()
|
||||
|
||||
console.log(`\n\n%c ======= ${title} ======= %c${moment().format('HH:mm:ss SSS')} \n`, `color:${randomColor};font-size:15`
|
||||
, `color:${getRandomColor()};font-size:15`, data,`\n\n =========================================`)
|
||||
window['console']['log'](`\n\n%c ======= ${title} ======= %c${moment().format('HH:mm:ss SSS')} \n`, `color:${randomColor};font-size:15`
|
||||
, `color:${getRandomColor()};font-size:15`)
|
||||
window['console']['log'](``)
|
||||
window['console']['log'](` `, data)
|
||||
window['console']['log'](`\n =========================================`)
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +34,11 @@ const updateObject = (oldObject: any, updatedProperties: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getStateSlice = (state: any) => state.toJS()['locale']
|
||||
|
||||
export default {
|
||||
logger,
|
||||
getRandomColor,
|
||||
updateObject
|
||||
updateObject,
|
||||
getStateSlice
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {List} from 'immutable'
|
||||
|
||||
// Get tags from post content
|
||||
export const detectTags: (content: string, character: string) => string[] = (content: string, character: string) => {
|
||||
@@ -27,3 +28,15 @@ export const sortObjectsDate = (objects: any) => {
|
||||
|
||||
return sortedObjects
|
||||
}
|
||||
|
||||
export const sortImuObjectsDate = (objects: List<Map<string, any>>) => {
|
||||
let sortedObjects = objects
|
||||
|
||||
// Sort posts with creation date
|
||||
return sortedObjects.sort((a: any, b: any) => {
|
||||
return parseInt(b.get('creationDate'),10) - parseInt(a.get('creationDate'),10)
|
||||
|
||||
})
|
||||
|
||||
// return sortedObjects
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { push } from 'react-router-redux'
|
||||
import {Map, List as ImuList} from 'immutable'
|
||||
|
||||
// - Material UI
|
||||
import List, {
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
@@ -119,7 +122,7 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
|
||||
/**
|
||||
* Circle name on change
|
||||
*/
|
||||
circleName: this.props.circle.name,
|
||||
circleName: this.props.circle.get('name', ''),
|
||||
/**
|
||||
* Save operation will be disable if user doesn't meet requirement
|
||||
*/
|
||||
@@ -210,9 +213,9 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
|
||||
let usersParsed: any = []
|
||||
|
||||
if (usersOfCircle) {
|
||||
Object.keys(usersOfCircle).forEach((userId, index) => {
|
||||
const { fullName } = usersOfCircle[userId]
|
||||
let avatar = usersOfCircle && usersOfCircle[userId] ? usersOfCircle[userId].avatar || '' : ''
|
||||
usersOfCircle.forEach((user: Map<string, any>, userId) => {
|
||||
const fullName = user.get('fullName')
|
||||
let avatar = user.get('avatar', '')
|
||||
usersParsed.push(
|
||||
<ListItem
|
||||
button
|
||||
@@ -303,9 +306,9 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
|
||||
<ListItemIcon className={classes.icon}>
|
||||
<SvgGroup />
|
||||
</ListItemIcon>
|
||||
<ListItemText inset primary={<span style={this.styles}>{this.props.circle.name}</span>} />
|
||||
<ListItemText inset primary={<span style={this.styles}>{this.props.circle.get('name')}</span>} />
|
||||
<ListItemSecondaryAction>
|
||||
{circle.isSystem ? null : rightIconMenu}
|
||||
{circle.get('isSystem') ? null : rightIconMenu}
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Collapse component='li' in={this.state.open} timeout='auto' unmountOnExit>
|
||||
@@ -363,27 +366,24 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICircleComponentProps) => {
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: ICircleComponentProps) => {
|
||||
const { circle, authorize, server } = state
|
||||
const { userTies } = circle
|
||||
const { uid } = state.authorize
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
const currentCircle = (circles ? circles[ownProps.id] : {}) as Circle
|
||||
const circleId = ownProps.circle.id!
|
||||
let usersOfCircle: { [userId: string]: UserTie } = {}
|
||||
Object.keys(userTies).forEach((userTieId) => {
|
||||
const theUserTie = userTies[userTieId] as UserTie
|
||||
if (theUserTie.circleIdList!.indexOf(ownProps.id) > -1) {
|
||||
usersOfCircle = {
|
||||
...usersOfCircle,
|
||||
[userTieId]: theUserTie
|
||||
}
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: ICircleComponentProps) => {
|
||||
const userTies: Map<string, any> = state.getIn(['circle', 'userTies'])
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
const circles: Map<string, Map<string, any>> = state.getIn(['circle', 'circleList'], {})
|
||||
const currentCircle: Map<string, any> = circles.get(ownProps.id, Map({}))
|
||||
const circleId = ownProps.circle.get('id')
|
||||
let usersOfCircle: Map<string, any> = Map({})
|
||||
userTies.forEach((userTie , userTieId) => {
|
||||
const theUserTie: Map<string, any> = userTie
|
||||
const circleList: ImuList<string> = theUserTie.getIn(['circleIdList'])
|
||||
if ( circleList.indexOf(ownProps.id) > -1) {
|
||||
usersOfCircle = usersOfCircle.set(userTieId!, theUserTie)
|
||||
}
|
||||
})
|
||||
return {
|
||||
usersOfCircle,
|
||||
openSetting: (state.circle && state.circle.openSetting && state.circle.openSetting[circleId]) ? state.circle.openSetting[circleId] : false,
|
||||
userInfo: state.user.info
|
||||
openSetting: state.getIn(['circle', 'openSetting', circleId], false),
|
||||
userInfo: state.getIn(['user', 'info'])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +1,57 @@
|
||||
import { Comment } from 'core/domain/comments'
|
||||
import { Profile } from 'core/domain/users'
|
||||
import { Circle, UserTie } from 'core/domain/circles'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
export interface ICircleComponentProps {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @type {Circle}
|
||||
* @memberof ICircleComponentProps
|
||||
* Circle
|
||||
*/
|
||||
circle: Circle
|
||||
circle: Map<string, any>
|
||||
|
||||
/**
|
||||
* Circle identifier
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ICircleComponentProps
|
||||
*/
|
||||
id: string
|
||||
|
||||
/**
|
||||
* User identifier
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ICircleComponentProps
|
||||
*/
|
||||
uid: string
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof ICircleComponentProps
|
||||
* Update circle
|
||||
*/
|
||||
updateCircle?: Function
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof ICircleComponentProps
|
||||
* Delete circle
|
||||
*/
|
||||
deleteCircle?: Function
|
||||
|
||||
/**
|
||||
* Users of current circle
|
||||
*/
|
||||
usersOfCircle?: {[userId: string]: UserTie}
|
||||
usersOfCircle?: Map<string, any>
|
||||
|
||||
/**
|
||||
* Close setting box of circle
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof ICircleComponentProps
|
||||
*/
|
||||
closeCircleSettings?: any
|
||||
|
||||
/**
|
||||
* Circle setting dialog is open {true} or not {false}
|
||||
*
|
||||
* @type {Function}
|
||||
* @memberof ICircleComponentProps
|
||||
*/
|
||||
openSetting?: boolean
|
||||
|
||||
/**
|
||||
* Change route location
|
||||
*
|
||||
* @memberof ICircleComponentProps
|
||||
*/
|
||||
goTo?: (url: string) => void
|
||||
|
||||
/**
|
||||
* Open setting box for a circle
|
||||
*
|
||||
* @memberof ICircleComponentProps
|
||||
*/
|
||||
openCircleSettings?: () => any
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import moment from 'moment/moment'
|
||||
import Linkify from 'react-linkify'
|
||||
import Popover from 'material-ui/Popover'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
import { Comment } from 'core/domain/comments'
|
||||
|
||||
@@ -285,8 +286,8 @@ export class CommentComponent extends Component<ICommentComponentProps, IComment
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
const { userId } = this.props.comment
|
||||
if (!this.props.isCommentOwner && !this.props.info![userId!]) {
|
||||
const { commentOwner } = this.props
|
||||
if (!this.props.isCommentOwner && !commentOwner) {
|
||||
this.props.getUserInfo!()
|
||||
}
|
||||
}
|
||||
@@ -432,15 +433,16 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICommentComponentProps) =>
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: any) => {
|
||||
const { uid } = state.authorize
|
||||
const avatar = state.user.info && state.user.info[ownProps.comment.userId] ? state.user.info[ownProps.comment.userId].avatar || '' : ''
|
||||
const fullName = state.user.info && state.user.info[ownProps.comment.userId] ? state.user.info[ownProps.comment.userId].fullName || '' : ''
|
||||
const mapStateToProps = (state: any, ownProps: ICommentComponentProps) => {
|
||||
const commentOwnerId = ownProps.comment.userId
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
const avatar = ownProps.comment.userAvatar
|
||||
const fullName = ownProps.comment.userDisplayName
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
uid: uid,
|
||||
isCommentOwner: (uid === ownProps.comment.userId),
|
||||
info: state.user.info,
|
||||
isCommentOwner: (uid === commentOwnerId),
|
||||
commentOwner: state.getIn(['user', 'info', commentOwnerId]),
|
||||
avatar,
|
||||
fullName
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@ export interface ICommentComponentProps {
|
||||
*/
|
||||
comment: Comment
|
||||
|
||||
/**
|
||||
* Comment owner
|
||||
*/
|
||||
commentOwner?: Profile
|
||||
|
||||
/**
|
||||
* Open profile editor
|
||||
*
|
||||
@@ -63,14 +68,6 @@ export interface ICommentComponentProps {
|
||||
*/
|
||||
getUserInfo?: () => void
|
||||
|
||||
/**
|
||||
* User profile
|
||||
*
|
||||
* @type {{[userId: string]: Profile}}
|
||||
* @memberof ICommentComponentProps
|
||||
*/
|
||||
info?: {[userId: string]: Profile}
|
||||
|
||||
/**
|
||||
* User full name
|
||||
*
|
||||
|
||||
@@ -6,6 +6,7 @@ import { NavLink } from 'react-router-dom'
|
||||
import { connect } from 'react-redux'
|
||||
import moment from 'moment/moment'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
import Paper from 'material-ui/Paper'
|
||||
import Button from 'material-ui/Button'
|
||||
@@ -30,11 +31,12 @@ import UserAvatar from 'components/userAvatar'
|
||||
|
||||
import { ICommentGroupComponentProps } from './ICommentGroupComponentProps'
|
||||
import { ICommentGroupComponentState } from './ICommentGroupComponentState'
|
||||
import { Comment } from 'core/domain/comments/comment'
|
||||
import { Comment } from 'core/domain/comments'
|
||||
import { ServerRequestModel } from 'models/server'
|
||||
import StringAPI from 'api/StringAPI'
|
||||
import { ServerRequestType } from 'constants/serverRequestType'
|
||||
import { ServerRequestStatusType } from 'store/actions/serverRequestStatusType'
|
||||
import { Profile } from 'core/domain/users'
|
||||
|
||||
const styles = (theme: any) => ({
|
||||
textField: {
|
||||
@@ -210,8 +212,8 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
||||
* @return {DOM} list of comments' DOM
|
||||
*/
|
||||
commentList = () => {
|
||||
const {classes} = this.props
|
||||
let comments = this.props.commentSlides
|
||||
const {classes, postId} = this.props
|
||||
let comments = Map(this.props.commentSlides!).toJS()
|
||||
if (comments) {
|
||||
comments = _.fromPairs(_.toPairs(comments)
|
||||
.sort((a: any, b: any) => parseInt(b[1].creationDate, 10) - parseInt(a[1].creationDate, 10)))
|
||||
@@ -229,10 +231,8 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
||||
parsedComments.push(parsedComments[0])
|
||||
}
|
||||
return parsedComments.map((comment, index) => {
|
||||
const { userInfo } = this.props
|
||||
|
||||
const commentAvatar = userInfo && userInfo[comment.userId!] ? userInfo[comment.userId!].avatar || '' : ''
|
||||
const commentFullName = userInfo && userInfo[comment.userId!] ? userInfo[comment.userId!].fullName || '' : ''
|
||||
const commentAvatar = comment.userAvatar
|
||||
const commentFullName = comment.userDisplayName
|
||||
|
||||
const commentBody = (
|
||||
<div style={{ outline: 'none', flex: 'auto', flexGrow: 1 }}>
|
||||
@@ -274,8 +274,8 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
||||
* @return {react element} return the DOM which rendered by component
|
||||
*/
|
||||
render () {
|
||||
const { comments, classes, postId, fullName, avatar, getCommentsRequest, open, commentSlides, translate } = this.props
|
||||
|
||||
const { classes, postId, fullName, avatar, commentsRequestStatus, open, commentSlides, translate } = this.props
|
||||
const comments: Map<string, Comment> = this.props.comments || Map({})
|
||||
/**
|
||||
* Comment list box
|
||||
*/
|
||||
@@ -314,20 +314,20 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
||||
</div>
|
||||
)
|
||||
|
||||
const showComments = ( comments && Object.keys(comments).length > 0
|
||||
const showComments = ( !comments.isEmpty()
|
||||
? (
|
||||
<Paper elevation={0} style={open ? { display: 'block', padding: '0px 0px' } : { display: 'none', padding: '12px 16px' }}>
|
||||
<CommentListComponent comments={comments!} isPostOwner={this.props.isPostOwner} disableComments={this.props.disableComments} postId={postId}/>
|
||||
</Paper>)
|
||||
: '')
|
||||
const loadComments = (( getCommentsRequest === undefined || (getCommentsRequest && getCommentsRequest!.status !== ServerRequestStatusType.OK)) ? <LinearProgress style={this.styles.progressbar} variant='indeterminate' /> : showComments)
|
||||
const loadComments = ((commentsRequestStatus === ServerRequestStatusType.OK) || !comments.isEmpty() ? showComments : <LinearProgress style={this.styles.progressbar} variant='indeterminate' />)
|
||||
/**
|
||||
* Return Elements
|
||||
*/
|
||||
return (
|
||||
<div key={postId + '-comments'}>
|
||||
<div style={commentSlides && Object.keys(commentSlides).length > 0 ? { display: 'block' } : { display: 'none' }}>
|
||||
<div key={postId + '-comments-group'}>
|
||||
<Divider />
|
||||
<div style={commentSlides && !commentSlides.isEmpty() ? { display: 'block' } : { display: 'none' }}>
|
||||
<Paper elevation={0} className='animate-top' style={!open ? { display: 'block' } : { display: 'none' }}>
|
||||
|
||||
<div style={{ position: 'relative', height: '60px' }} >
|
||||
@@ -339,11 +339,11 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
||||
</div>
|
||||
</div>
|
||||
</Paper>
|
||||
|
||||
</div>
|
||||
{
|
||||
open ? loadComments : ''
|
||||
}
|
||||
|
||||
</div>
|
||||
{
|
||||
(!this.props.disableComments && open )
|
||||
? commentWriteBox
|
||||
@@ -377,19 +377,20 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICommentGroupComponentProps
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: ICommentGroupComponentProps) => {
|
||||
const { post, user, authorize, server } = state
|
||||
const {request} = server
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: ICommentGroupComponentProps) => {
|
||||
const { ownerPostUserId, postId } = ownProps
|
||||
const commentSlides = post.userPosts[ownerPostUserId] && post.userPosts[ownerPostUserId][postId] ? post.userPosts[ownerPostUserId][postId].comments : {}
|
||||
const getCommentsRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CommentGetComments, postId)] : null
|
||||
const uid = state.getIn(['authorize', 'uid'], 0)
|
||||
const requestId = StringAPI.createServerRequestId(ServerRequestType.CommentGetComments, postId)
|
||||
const commentsRequestStatus = state.getIn(['server', 'request', requestId])
|
||||
const commentSlides = state.getIn(['post', 'userPosts', ownerPostUserId, postId, 'comments'])
|
||||
const user = state.getIn(['user', 'info', uid])
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
getCommentsRequest,
|
||||
translate: getTranslate(state.get('locale')),
|
||||
commentsRequestStatus : commentsRequestStatus ? commentsRequestStatus.status : ServerRequestStatusType.NoAction,
|
||||
commentSlides,
|
||||
avatar: user.info && user.info[state.authorize.uid] ? user.info[authorize.uid].avatar || '' : '',
|
||||
fullName: user.info && user.info[state.authorize.uid] ? user.info[authorize.uid].fullName || '' : '',
|
||||
userInfo: user.info
|
||||
avatar: user.avatar || '',
|
||||
fullName: user.fullName || '',
|
||||
userInfo: state.getIn(['user', 'info'])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Profile } from 'core/domain/users'
|
||||
import { Comment } from 'core/domain/comments'
|
||||
import { ServerRequestModel } from 'models/server'
|
||||
import { ServerRequestStatusType } from 'store/actions/serverRequestStatusType'
|
||||
import {Map} from 'immutable'
|
||||
export interface ICommentGroupComponentProps {
|
||||
|
||||
/**
|
||||
@@ -9,15 +11,12 @@ export interface ICommentGroupComponentProps {
|
||||
* @type {{[commentId: string]: Comment}}
|
||||
* @memberof ICommentGroupComponentProps
|
||||
*/
|
||||
comments?: {[commentId: string]: Comment}
|
||||
comments?: Map<string, Comment>
|
||||
|
||||
/**
|
||||
* Commnets show on slide preview
|
||||
*
|
||||
* @type {{[commentId: string]: Comment}}
|
||||
* @memberof ICommentGroupComponentProps
|
||||
*/
|
||||
commentSlides?: {[commentId: string]: Comment}
|
||||
commentSlides?: Map<string, Comment>
|
||||
|
||||
/**
|
||||
* The post identifier which comment belong to
|
||||
@@ -33,7 +32,7 @@ export interface ICommentGroupComponentProps {
|
||||
* @type {{[userId: string]: Profile}}
|
||||
* @memberof ICommentGroupComponentProps
|
||||
*/
|
||||
userInfo?: {[userId: string]: Profile}
|
||||
userInfo?: Map<string, Profile>
|
||||
|
||||
/**
|
||||
* Comment group is open {true} or not {false}
|
||||
@@ -102,7 +101,7 @@ export interface ICommentGroupComponentProps {
|
||||
/**
|
||||
* Get post comments request payload
|
||||
*/
|
||||
getCommentsRequest?: ServerRequestModel
|
||||
commentsRequestStatus?: ServerRequestStatusType
|
||||
|
||||
/**
|
||||
* Styles
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Material UI
|
||||
import { withStyles } from 'material-ui/styles'
|
||||
@@ -66,14 +67,15 @@ export class CommentListComponent extends Component<ICommentListComponentProps,
|
||||
* @return {DOM} list of comments' DOM
|
||||
*/
|
||||
commentList = () => {
|
||||
let {comments, commentsEditorStatus} = this.props
|
||||
if (comments) {
|
||||
let comments = Map<string, Comment>(this.props.comments)
|
||||
let commentsEditorStatus = Map<string, boolean>(this.props.commentsEditorStatus!)
|
||||
if (!comments.isEmpty()) {
|
||||
|
||||
let parsedComments: Comment[] = []
|
||||
Object.keys(comments).forEach((commentId) => {
|
||||
comments.forEach((comment, commentId) => {
|
||||
parsedComments.push({
|
||||
id: commentId,
|
||||
...comments[commentId]
|
||||
...Map(comment!).toJS()
|
||||
})
|
||||
})
|
||||
let sortedComments = PostAPI.sortObjectsDate(parsedComments)
|
||||
@@ -86,7 +88,7 @@ export class CommentListComponent extends Component<ICommentListComponentProps,
|
||||
comment={comment}
|
||||
isPostOwner={this.props.isPostOwner}
|
||||
disableComments={this.props.disableComments}
|
||||
editorStatus={(commentsEditorStatus![comment.id!]) || false}
|
||||
editorStatus={(commentsEditorStatus.get(comment.id!, false))}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -100,11 +102,11 @@ export class CommentListComponent extends Component<ICommentListComponentProps,
|
||||
* @return {react element} return the DOM which rendered by component
|
||||
*/
|
||||
render () {
|
||||
const {classes} = this.props
|
||||
const {classes, postId} = this.props
|
||||
|
||||
return (
|
||||
|
||||
<List className={classes.list}>
|
||||
<List key={`comment-list-${postId}`} className={classes.list}>
|
||||
|
||||
{this.commentList()}
|
||||
</List>
|
||||
@@ -130,9 +132,8 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICommentListComponentProps)
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: ICommentListComponentProps) => {
|
||||
const { comment } = state
|
||||
const commentsEditorStatus: { [commentId: string]: Comment } = comment.editorStatus[ownProps.postId] || {}
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: ICommentListComponentProps) => {
|
||||
const commentsEditorStatus = state.getIn(['comment', 'editorStatus', ownProps.postId ], {})
|
||||
return {
|
||||
commentsEditorStatus
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Comment } from 'core/domain/comments'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
export interface ICommentListComponentProps {
|
||||
|
||||
@@ -8,7 +9,7 @@ export interface ICommentListComponentProps {
|
||||
* @type {{[commentId: string]: Comment}}
|
||||
* @memberof ICommentListComponentProps
|
||||
*/
|
||||
comments: {[commentId: string]: Comment}
|
||||
comments: Map<string, Comment>
|
||||
|
||||
/**
|
||||
* Comments editor status
|
||||
|
||||
@@ -10,6 +10,7 @@ import MomentLocaleUtils, {
|
||||
formatDate,
|
||||
parseDate,
|
||||
} from 'react-day-picker/moment'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
import { grey } from 'material-ui/colors'
|
||||
import IconButton from 'material-ui/IconButton'
|
||||
@@ -294,9 +295,9 @@ export class EditProfileComponent extends Component<IEditProfileComponentProps,
|
||||
*/
|
||||
handleUpdate = () => {
|
||||
const { fullNameInput, tagLineInput, avatar, banner, selectedBirthday, companyName, webUrl, twitterId } = this.state
|
||||
const { info } = this.props
|
||||
const { info, update } = this.props
|
||||
|
||||
if (this.state.fullNameInput.trim() === '') {
|
||||
if (fullNameInput.trim() === '') {
|
||||
this.setState({
|
||||
fullNameInputError: 'This field is required'
|
||||
})
|
||||
@@ -305,7 +306,7 @@ export class EditProfileComponent extends Component<IEditProfileComponentProps,
|
||||
fullNameInputError: ''
|
||||
})
|
||||
|
||||
this.props.update!({
|
||||
update!({
|
||||
fullName: fullNameInput,
|
||||
tagLine: tagLineInput,
|
||||
avatar: avatar,
|
||||
@@ -562,13 +563,14 @@ const mapDispatchToProps = (dispatch: any, ownProps: IEditProfileComponentProps)
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IEditProfileComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IEditProfileComponentProps) => {
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
return {
|
||||
currentLanguage: getActiveLanguage(state.locale).code,
|
||||
translate: getTranslate(state.locale),
|
||||
open: state.user.openEditProfile,
|
||||
info: state.user.info[state.authorize.uid],
|
||||
avatarURL: state.imageGallery.imageURLList
|
||||
currentLanguage: getActiveLanguage(state.get('locale')).code,
|
||||
translate: getTranslate(state.get('locale')),
|
||||
open: state.getIn(['user', 'openEditProfile'], false),
|
||||
info: state.getIn(['user', 'info', uid]),
|
||||
avatarURL: state.getIn(['imageGallery', 'imageURLList'])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import PropTypes from 'prop-types'
|
||||
import Paper from 'material-ui/Paper'
|
||||
import InfiniteScroll from 'react-infinite-scroller'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
import UserBoxList from 'components/userBoxList'
|
||||
@@ -16,6 +17,7 @@ import LoadMoreProgressComponent from 'layouts/loadMoreProgress'
|
||||
import * as userActions from 'store/actions/userActions'
|
||||
import { IFindPeopleComponentProps } from './IFindPeopleComponentProps'
|
||||
import { IFindPeopleComponentState } from './IFindPeopleComponentState'
|
||||
import { UserTie } from 'core/domain/circles/userTie'
|
||||
|
||||
/**
|
||||
* Create component class
|
||||
@@ -50,7 +52,7 @@ export class FindPeopleComponent extends Component<IFindPeopleComponentProps, IF
|
||||
*/
|
||||
render () {
|
||||
const {hasMorePeople, translate} = this.props
|
||||
|
||||
const peopleInfo = Map<string, UserTie>(this.props.peopleInfo!)
|
||||
return (
|
||||
<div>
|
||||
<InfiniteScroll
|
||||
@@ -63,11 +65,11 @@ export class FindPeopleComponent extends Component<IFindPeopleComponentProps, IF
|
||||
|
||||
<div className='tracks'>
|
||||
|
||||
{this.props.peopleInfo && Object.keys(this.props.peopleInfo).length !== 0 ? (<div>
|
||||
{peopleInfo && peopleInfo.count() > 0 ? (<div>
|
||||
<div className='profile__title'>
|
||||
{translate!('people.suggestionsForYouLabel')}
|
||||
</div>
|
||||
<UserBoxList users={this.props.peopleInfo}/>
|
||||
<UserBoxList users={peopleInfo}/>
|
||||
<div style={{ height: '24px' }}></div>
|
||||
</div>) : (<div className='g__title-center'>
|
||||
{translate!('people.nothingToShowLabel')}
|
||||
@@ -98,11 +100,13 @@ const mapDispatchToProps = (dispatch: any, ownProps: IFindPeopleComponentProps)
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IFindPeopleComponentProps) => {
|
||||
const {people, info} = state.user
|
||||
const people = state.getIn(['user', 'people'])
|
||||
const hasMorePeople = state.getIn(['user', 'people', 'hasMoreData' ], true)
|
||||
const info: Map<string, UserTie> = state.getIn(['user', 'info'])
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
peopleInfo: info,
|
||||
hasMorePeople: people.hasMoreData
|
||||
hasMorePeople
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Profile } from 'core/domain/users/profile'
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
|
||||
export interface IFindPeopleComponentProps {
|
||||
|
||||
@@ -11,11 +12,8 @@ export interface IFindPeopleComponentProps {
|
||||
|
||||
/**
|
||||
* Users' profile
|
||||
*
|
||||
* @type {{[userId: string]: Profile}}
|
||||
* @memberof IFindPeopleComponentProps
|
||||
*/
|
||||
peopleInfo?: {[userId: string]: Profile}
|
||||
peopleInfo?: Map<string, UserTie>
|
||||
|
||||
/**
|
||||
* If there are more people {true} or not {false}
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
import UserBoxList from 'components/userBoxList'
|
||||
@@ -46,13 +47,14 @@ export class FollowersComponent extends Component<IFollowersComponentProps,IFoll
|
||||
*/
|
||||
render () {
|
||||
const {translate} = this.props
|
||||
const followers = this.props.followers!
|
||||
return (
|
||||
<div>
|
||||
{(this.props.followers && Object.keys(this.props.followers).length !== 0) ? (<div>
|
||||
{(followers && followers.keySeq().count() !== 0) ? (<div>
|
||||
<div className='profile__title'>
|
||||
{translate!('people.followersLabel')}
|
||||
</div>
|
||||
<UserBoxList users={this.props.followers} />
|
||||
<UserBoxList users={followers} />
|
||||
<div style={{ height: '24px' }}></div>
|
||||
</div>)
|
||||
: (<div className='g__title-center'>
|
||||
@@ -81,13 +83,13 @@ const mapDispatchToProps = (dispatch: any,ownProps: IFollowersComponentProps) =>
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any,ownProps: IFollowersComponentProps) => {
|
||||
const {circle, authorize, server} = state
|
||||
const { uid } = state.authorize
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
const followers = circle ? circle.userTieds : {}
|
||||
const mapStateToProps = (state: Map<string, any>,ownProps: IFollowersComponentProps) => {
|
||||
|
||||
const uid = state.getIn(['authorize', 'uid'], 0)
|
||||
const circles: { [circleId: string]: Circle } = state.getIn(['circle', 'circleList'], {})
|
||||
const followers = state.getIn(['circle', 'userTieds'], {})
|
||||
return{
|
||||
translate: getTranslate(state.locale),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
followers
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
export interface IFollowersComponentProps {
|
||||
|
||||
/**
|
||||
* User followers info
|
||||
*
|
||||
* @type {{[userId: string]: UserTie}}
|
||||
* @memberof IFindPeopleComponentProps
|
||||
*/
|
||||
followers?: {[userId: string]: UserTie}
|
||||
followers?: Map<string, UserTie>
|
||||
|
||||
/**
|
||||
* Translate to locale string
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
import UserBoxList from 'components/userBoxList'
|
||||
@@ -46,13 +47,14 @@ export class FollowingComponent extends Component<IFollowingComponentProps,IFoll
|
||||
*/
|
||||
render () {
|
||||
const {translate} = this.props
|
||||
const followingUsers = Map(this.props.followingUsers!)
|
||||
return (
|
||||
<div>
|
||||
{(this.props.followingUsers && Object.keys(this.props.followingUsers).length !== 0 ) ? (<div>
|
||||
{(followingUsers && followingUsers.keySeq().count() !== 0 ) ? (<div>
|
||||
<div className='profile__title'>
|
||||
{translate!('people.followingLabel')}
|
||||
</div>
|
||||
<UserBoxList users={this.props.followingUsers} />
|
||||
<UserBoxList users={followingUsers} />
|
||||
<div style={{ height: '24px' }}></div>
|
||||
|
||||
</div>) : (<div className='g__title-center'>
|
||||
@@ -81,13 +83,13 @@ const mapDispatchToProps = (dispatch: any,ownProp: IFollowingComponentProps) =>
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any,ownProps: IFollowingComponentProps) => {
|
||||
const {circle, authorize, server} = state
|
||||
const { uid } = state.authorize
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
const followingUsers = circle ? circle.userTies : {}
|
||||
const mapStateToProps = (state: Map<string, any>,ownProps: IFollowingComponentProps) => {
|
||||
|
||||
const uid = state.getIn(['authorize', 'uid'], 0)
|
||||
const circles: { [circleId: string]: Circle } = state.getIn(['circle', 'circleList'], {})
|
||||
const followingUsers = state.getIn(['circle', 'userTies'], {})
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
uid,
|
||||
circles,
|
||||
followingUsers
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
export interface IFollowingComponentProps {
|
||||
|
||||
followingUsers?: {[userId: string]: UserTie}
|
||||
followingUsers?: Map<string, UserTie>
|
||||
|
||||
/**
|
||||
* Translate to locale string
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { Component } from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { connect } from 'react-redux'
|
||||
import classNames from 'classnames'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Material UI
|
||||
import SvgDehaze from 'material-ui-icons/Dehaze'
|
||||
@@ -256,18 +257,20 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IHomeHeaderComponentPr
|
||||
}
|
||||
|
||||
// - Map state to props
|
||||
const mapStateToProps = (state: any, ownProps: IHomeHeaderComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string,any>, ownProps: IHomeHeaderComponentProps) => {
|
||||
|
||||
let notifyCount = state.notify.userNotifies
|
||||
? Object
|
||||
.keys(state.notify.userNotifies)
|
||||
.filter((key) => !state.notify.userNotifies[key].isSeen).length
|
||||
const uid = state.getIn(['authorize', 'uid'], 0)
|
||||
const userNotifies: Map<string, any> = state.getIn(['notify','userNotifies'])
|
||||
let notifyCount = userNotifies
|
||||
? userNotifies
|
||||
.filter((notification) => !notification.get('isSeen', false)).count()
|
||||
: 0
|
||||
const user = state.getIn(['user', 'info', uid], {})
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
avatar: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].avatar : '',
|
||||
fullName: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].fullName : '',
|
||||
title: state.global.headerTitle,
|
||||
translate: getTranslate(state.get('locale')),
|
||||
avatar: user.avatar || '',
|
||||
fullName: user.fullName || '',
|
||||
title: state.getIn(['global', 'headerTitle'], ''),
|
||||
notifyCount
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Image } from 'core/domain/imageGallery'
|
||||
import {Map, Collection, List} from 'immutable'
|
||||
|
||||
export interface IImageGalleryComponentProps {
|
||||
|
||||
@@ -33,11 +34,8 @@ export interface IImageGalleryComponentProps {
|
||||
|
||||
/**
|
||||
* List of image in image gallery
|
||||
*
|
||||
* @type {Image[]}
|
||||
* @memberof IImageGalleryComponentProps
|
||||
*/
|
||||
images?: Image[]
|
||||
images?: List<Image>
|
||||
|
||||
/**
|
||||
* Styles
|
||||
|
||||
@@ -13,6 +13,7 @@ import { grey } from 'material-ui/colors'
|
||||
import { withStyles } from 'material-ui/styles'
|
||||
import uuid from 'uuid'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import actions
|
||||
import * as imageGalleryActions from 'store/actions/imageGalleryActions'
|
||||
@@ -161,7 +162,6 @@ export class ImageGalleryComponent extends Component<IImageGalleryComponentProps
|
||||
}
|
||||
|
||||
imageList = () => {
|
||||
|
||||
return this.props.images!.map((image: Image, index) => {
|
||||
|
||||
return (
|
||||
@@ -254,11 +254,13 @@ const mapDispatchToProps = (dispatch: any, ownProps: IImageGalleryComponentProps
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any) => {
|
||||
const mapStateToProps = (state: Map<string, any>) => {
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
const currentUser = state.getIn(['user', 'info', uid])
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
images: state.imageGallery.images,
|
||||
avatar: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].avatar : ''
|
||||
translate: getTranslate(state.get('locale')),
|
||||
images: state.getIn(['imageGallery', 'images']),
|
||||
avatar: currentUser ? currentUser.avatar : ''
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { connect } from 'react-redux'
|
||||
import SvgImage from 'material-ui-icons/Image'
|
||||
import { withStyles } from 'material-ui/styles'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
|
||||
@@ -121,11 +122,11 @@ const mapDispatchToProps = (dispatch: any, ownProps: IImgComponentProps) => {
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IImgComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IImgComponentProps) => {
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
avatarURL: state.imageGallery.imageURLList,
|
||||
imageRequests: state.imageGallery.imageRequests
|
||||
translate: getTranslate(state.get('locale')),
|
||||
avatarURL: state.getIn(['imageGallery', 'imageURLList']),
|
||||
imageRequests: state.getIn(['imageGallery', 'imageRequests'])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import SvgImage from 'material-ui-icons/Image'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
|
||||
@@ -153,9 +154,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: IImgCoverComponentProps) =>
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IImgCoverComponentProps) => {
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
avatarURL: state.imageGallery.imageURLList,
|
||||
imageRequests: state.imageGallery.imageRequests
|
||||
translate: getTranslate(state.get('locale'))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
export interface IMasterLoadingComponentProps {
|
||||
|
||||
/**
|
||||
* Loading is active {true} or not {false}
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof IMasterLoadingComponentProps
|
||||
*/
|
||||
activeLoading: boolean
|
||||
|
||||
handleLoading: (status: boolean) => void
|
||||
error?: boolean
|
||||
timedOut?: boolean
|
||||
pastDelay?: boolean
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
import React, { Component } from 'react'
|
||||
import { CircularProgress } from 'material-ui/Progress'
|
||||
import Dialog from 'material-ui/Dialog'
|
||||
import red from 'material-ui/colors/red'
|
||||
import { IMasterLoadingComponentProps } from './IMasterLoadingComponentProps'
|
||||
import { IMasterLoadingComponentState } from './IMasterLoadingComponentState'
|
||||
import Grid from 'material-ui/Grid/Grid'
|
||||
import { Typography } from 'material-ui'
|
||||
|
||||
// - Import app components
|
||||
|
||||
@@ -11,26 +14,78 @@ import { IMasterLoadingComponentState } from './IMasterLoadingComponentState'
|
||||
export default class MasterLoadingComponent extends Component<IMasterLoadingComponentProps, IMasterLoadingComponentState> {
|
||||
|
||||
// Constructor
|
||||
constructor (props: IMasterLoadingComponentProps) {
|
||||
constructor(props: IMasterLoadingComponentProps) {
|
||||
super(props)
|
||||
// Binding functions to `this`
|
||||
|
||||
}
|
||||
|
||||
loadProgress() {
|
||||
const { error, timedOut, pastDelay } = this.props
|
||||
if (error) {
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<CircularProgress style={{ color: red[500] }} size={50} />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant='title' color='primary' style={{ marginLeft: '15px' }} >
|
||||
Unexpected Error Happened ...
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
} else if (timedOut) {
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<CircularProgress style={{ color: red[500] }} size={50} />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant='title' color='primary' style={{ marginLeft: '15px' }} >
|
||||
It takes long time ...
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
} else if (pastDelay) {
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<CircularProgress size={50} />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant='title' color='primary' style={{ marginLeft: '15px' }} >
|
||||
Loading...
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<CircularProgress size={50} />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant='title' color='primary' style={{ marginLeft: '15px' }} >
|
||||
Loading...
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Render app DOM component
|
||||
render () {
|
||||
const {activeLoading} = this.props
|
||||
render() {
|
||||
return (
|
||||
|
||||
<div className='mLoading__loading' style={{ display: (activeLoading ? 'flex' : 'none') }}>
|
||||
<CircularProgress
|
||||
color='secondary'
|
||||
size={50}
|
||||
variant='determinate'
|
||||
value={25}
|
||||
min={0}
|
||||
max={50}
|
||||
/>
|
||||
<div className='mLoading__loading'>
|
||||
{
|
||||
this.loadProgress()
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
)
|
||||
|
||||
@@ -1,44 +1,30 @@
|
||||
import { Profile } from 'core/domain/users'
|
||||
import { Notification } from 'core/domain/notifications'
|
||||
|
||||
import {Map} from 'immutable'
|
||||
export interface INotifyComponentProps {
|
||||
|
||||
/**
|
||||
* Notifications
|
||||
*
|
||||
* @type {{[notificationId: string]: Notification}}
|
||||
* @memberof INotifyComponentProps
|
||||
*/
|
||||
notifications?: {[notificationId: string]: Notification}
|
||||
notifications?: Map<string, any>
|
||||
|
||||
/**
|
||||
* Users' profile
|
||||
*
|
||||
* @type {{[userId: string]: Profile}}
|
||||
* @memberof INotifyComponentProps
|
||||
*/
|
||||
info?: {[userId: string]: Profile}
|
||||
info?: Map<string, Profile>
|
||||
|
||||
/**
|
||||
* Close notification
|
||||
*
|
||||
* @memberof INotifyComponentProps
|
||||
*/
|
||||
onRequestClose: () => void
|
||||
|
||||
/**
|
||||
* User notifications popover is opem {true} or not {false}
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof INotifyComponentProps
|
||||
*/
|
||||
open: boolean
|
||||
|
||||
/**
|
||||
* Keep element
|
||||
*
|
||||
* @type {*}
|
||||
* @memberof INotifyComponentProps
|
||||
*/
|
||||
anchorEl?: any
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { withStyles } from 'material-ui/styles'
|
||||
import Typography from 'material-ui/Typography'
|
||||
import Paper from 'material-ui/Paper'
|
||||
import List, { ListItem, ListItemSecondaryAction, ListItemText } from 'material-ui/List'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
import NotifyItem from 'components/notifyItem'
|
||||
@@ -52,7 +53,8 @@ const styles = (theme: any) => ({
|
||||
},
|
||||
list: {
|
||||
maxHeight: 380,
|
||||
overflowY: 'auto'
|
||||
overflowY: 'auto',
|
||||
width: '98%'
|
||||
|
||||
},
|
||||
fullPageXs: {
|
||||
@@ -106,20 +108,22 @@ export class NotifyComponent extends Component<INotifyComponentProps, INotifyCom
|
||||
}
|
||||
|
||||
notifyItemList = () => {
|
||||
let { notifications, info, onRequestClose } = this.props
|
||||
let { info, onRequestClose } = this.props
|
||||
let notifications: Map<string, Map<string, any>> = this.props.notifications!
|
||||
let parsedDOM: any[] = []
|
||||
if (notifications) {
|
||||
Object.keys(notifications).forEach((key) => {
|
||||
const { notifierUserId } = notifications![key]
|
||||
notifications.forEach((notification, key) => {
|
||||
const notifierUserId = notification!.get('notifierUserId')
|
||||
const userInfo = info!.get(notifierUserId)
|
||||
parsedDOM.push(
|
||||
<NotifyItem
|
||||
key={key}
|
||||
description={(notifications![key] ? notifications![key].description || '' : '')}
|
||||
fullName={(info![notifierUserId] ? info![notifierUserId].fullName || '' : '')}
|
||||
avatar={(info![notifierUserId] ? info![notifierUserId].avatar || '' : '')}
|
||||
id={key}
|
||||
isSeen={(notifications![key] ? notifications![key].isSeen || false : false)}
|
||||
url={(notifications![key] ? notifications![key].url || '' : '')}
|
||||
description={notification!.get('description', '')}
|
||||
fullName={(userInfo ? userInfo.fullName || '' : '')}
|
||||
avatar={(userInfo ? userInfo.avatar || '' : '')}
|
||||
id={key!}
|
||||
isSeen={notification!.get('isSeen', false)}
|
||||
url={notification!.get('url')}
|
||||
notifierUserId={notifierUserId}
|
||||
closeNotify={onRequestClose}
|
||||
/>
|
||||
@@ -179,10 +183,10 @@ const mapDispatchToProps = (dispatch: any, ownProps: INotifyComponentProps) => {
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: INotifyComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: INotifyComponentProps) => {
|
||||
return {
|
||||
notifications: state.notify.userNotifies,
|
||||
info: state.user.info
|
||||
notifications: state.getIn(['notify', 'userNotifies']),
|
||||
info: state.getIn(['user', 'info'])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { Comment } from 'core/domain/comments'
|
||||
import { Post } from 'core/domain/posts/post'
|
||||
|
||||
import {Map} from 'immutable'
|
||||
export interface IPostComponentProps {
|
||||
|
||||
/**
|
||||
* Post object
|
||||
*
|
||||
* @type {Post}
|
||||
* @memberof IPostComponentProps
|
||||
*/
|
||||
post: Post
|
||||
post: Map<string, any>
|
||||
|
||||
/**
|
||||
* Owner's post avatar
|
||||
@@ -113,7 +110,7 @@ export interface IPostComponentProps {
|
||||
* @type {{[commentId: string]: Comment}}
|
||||
* @memberof ICommentGroupComponentProps
|
||||
*/
|
||||
commentList?: {[commentId: string]: Comment}
|
||||
commentList?: Map<string, Comment>
|
||||
|
||||
/**
|
||||
* Styles
|
||||
|
||||
@@ -8,9 +8,11 @@ import moment from 'moment/moment'
|
||||
import Linkify from 'react-linkify'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Material UI
|
||||
import { Card, CardActions, CardHeader, CardMedia, CardContent } from 'material-ui'
|
||||
import Card, { CardActions, CardHeader, CardMedia, CardContent } from 'material-ui/Card'
|
||||
import { LinearProgress } from 'material-ui/Progress'
|
||||
import Typography from 'material-ui/Typography'
|
||||
import SvgShare from 'material-ui-icons/Share'
|
||||
import SvgComment from 'material-ui-icons/Comment'
|
||||
@@ -65,7 +67,8 @@ const styles = (theme: any) => ({
|
||||
color: 'rgb(134, 129, 129)',
|
||||
fontSize: 10,
|
||||
fontWeight: 400,
|
||||
padding: 2
|
||||
padding: 2,
|
||||
zIndex: 1
|
||||
},
|
||||
commentCounter: {
|
||||
color: 'rgb(134, 129, 129)',
|
||||
@@ -125,7 +128,7 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
/**
|
||||
* Post text
|
||||
*/
|
||||
text: post.body ? post.body : '',
|
||||
text: post.get('body', ''),
|
||||
/**
|
||||
* It's true if whole the text post is visible
|
||||
*/
|
||||
@@ -141,11 +144,11 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
/**
|
||||
* If it's true comment will be disabled on post
|
||||
*/
|
||||
disableComments: post.disableComments!,
|
||||
disableComments: post.get('disableComments', false),
|
||||
/**
|
||||
* If it's true share will be disabled on post
|
||||
*/
|
||||
disableSharing: post.disableSharing!,
|
||||
disableSharing: post.get('disableSharing', false),
|
||||
/**
|
||||
* Title of share post
|
||||
*/
|
||||
@@ -187,7 +190,8 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
*/
|
||||
handleOpenComments = () => {
|
||||
const { getPostComments, commentList, post } = this.props
|
||||
const { id, ownerUserId } = post
|
||||
const id = post.get('id')
|
||||
const ownerUserId = post.get('ownerUserId')
|
||||
if (!commentList) {
|
||||
getPostComments!(ownerUserId!, id!)
|
||||
}
|
||||
@@ -228,14 +232,13 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
*/
|
||||
handleDelete = () => {
|
||||
const { post } = this.props
|
||||
this.props.delete!(post.id!)
|
||||
this.props.delete!(post.get('id'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Open post menu
|
||||
*/
|
||||
openPostMenu = (event: any) => {
|
||||
console.log(event.currentTarget)
|
||||
this.setState({
|
||||
postMenuAnchorEl: event.currentTarget,
|
||||
isPostMenuOpen: true
|
||||
@@ -274,7 +277,7 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
*/
|
||||
handleOpenShare = () => {
|
||||
const {post} = this.props
|
||||
copy(`${location.origin}/${post.ownerUserId}/posts/${post.id}`)
|
||||
copy(`${location.origin}/${post.get('ownerUserId')}/posts/${post.get('id')}`)
|
||||
this.setState({
|
||||
shareOpen: true
|
||||
})
|
||||
@@ -360,12 +363,12 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
<MenuItem onClick={this.handleOpenPostWrite} > {translate!('post.edit')} </MenuItem>
|
||||
<MenuItem onClick={this.handleDelete} > {translate!('post.delete')} </MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => this.props.toggleDisableComments!(!post.disableComments)} >
|
||||
{post.disableComments ? translate!('post.enableComments') : translate!('post.disableComments')}
|
||||
onClick={() => this.props.toggleDisableComments!(!post.get('disableComments'))} >
|
||||
{post.get('disableComments') ? translate!('post.enableComments') : translate!('post.disableComments')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => this.props.toggleSharingComments!(!post.disableSharing)} >
|
||||
{post.disableSharing ? translate!('post.enableSharing') : translate!('post.disableSharing')}
|
||||
onClick={() => this.props.toggleSharingComments!(!post.get('disableSharing'))} >
|
||||
{post.get('disableSharing') ? translate!('post.enableSharing') : translate!('post.disableSharing')}
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Paper>
|
||||
@@ -375,13 +378,23 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
</Manager>
|
||||
)
|
||||
|
||||
const { ownerUserId, ownerDisplayName, creationDate, image, body } = post
|
||||
const {
|
||||
ownerUserId,
|
||||
ownerDisplayName,
|
||||
creationDate,
|
||||
image,
|
||||
body,
|
||||
id,
|
||||
disableComments,
|
||||
commentCounter,
|
||||
disableSharing ,
|
||||
} = post.toJS()
|
||||
// Define variables
|
||||
return (
|
||||
<Card>
|
||||
<Card key={`post-component-${id}`}>
|
||||
<CardHeader
|
||||
title={<NavLink to={`/${ownerUserId}`}>{ownerDisplayName}</NavLink>}
|
||||
subheader={moment.unix(creationDate!).fromNow() + ' | ' + translate!('post.public')}
|
||||
subheader={creationDate ? moment.unix(creationDate!).fromNow() + ' | ' + translate!('post.public') : <LinearProgress color='primary' />}
|
||||
avatar={<NavLink to={`/${ownerUserId}`}><UserAvatar fullName={fullName!} fileName={avatar!} size={36} /></NavLink>}
|
||||
action={isPostOwner ? rightIconMenu : ''}
|
||||
>
|
||||
@@ -426,16 +439,16 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
<div className={classes.voteCounter}> {this.props.voteCount! > 0 ? this.props.voteCount : ''} </div>
|
||||
</IconButton>
|
||||
</div>
|
||||
{!post.disableComments ?
|
||||
{!disableComments ?
|
||||
(<div style={{ display: 'inherit' }}><IconButton
|
||||
className={classes.iconButton}
|
||||
onClick={this.handleOpenComments}
|
||||
aria-label='Comment'>
|
||||
<SvgComment />
|
||||
<div className={classes.commentCounter}>{post.commentCounter! > 0 ? post.commentCounter : ''} </div>
|
||||
<div className={classes.commentCounter}>{commentCounter! > 0 ? commentCounter : ''} </div>
|
||||
</IconButton>
|
||||
</div>) : ''}
|
||||
{!post.disableSharing ? (<IconButton
|
||||
{!disableSharing ? (<IconButton
|
||||
className={classes.iconButton}
|
||||
onClick={this.handleOpenShare}
|
||||
aria-label='Comment'>
|
||||
@@ -444,7 +457,7 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
|
||||
</CardActions>
|
||||
|
||||
<CommentGroup open={this.state.openComments} comments={commentList} ownerPostUserId={post.ownerUserId!} onToggleRequest={this.handleOpenComments} isPostOwner={this.props.isPostOwner!} disableComments={post.disableComments!} postId={post.id!} />
|
||||
<CommentGroup open={this.state.openComments} comments={commentList} ownerPostUserId={ownerUserId!} onToggleRequest={this.handleOpenComments} isPostOwner={this.props.isPostOwner!} disableComments={disableComments!} postId={id} />
|
||||
|
||||
<ShareDialog
|
||||
onClose={this.handleCloseShare}
|
||||
@@ -477,16 +490,14 @@ export class PostComponent extends Component<IPostComponentProps, IPostComponent
|
||||
const mapDispatchToProps = (dispatch: any, ownProps: IPostComponentProps) => {
|
||||
const { post } = ownProps
|
||||
return {
|
||||
vote: () => dispatch(voteActions.dbAddVote(post.id!, post.ownerUserId!)),
|
||||
unvote: () => dispatch(voteActions.dbDeleteVote(post.id!, post.ownerUserId!)),
|
||||
vote: () => dispatch(voteActions.dbAddVote(post.get('id'), post.get('ownerUserId'))),
|
||||
unvote: () => dispatch(voteActions.dbDeleteVote(post.get('id'), post.get('ownerUserId'))),
|
||||
delete: (id: string) => dispatch(postActions.dbDeletePost(id)),
|
||||
toggleDisableComments: (status: boolean) => {
|
||||
post.disableComments = status
|
||||
dispatch(postActions.dbUpdatePost(post, (x: any) => x))
|
||||
dispatch(postActions.dbUpdatePost(post.set('disableComments', status), (x: any) => x))
|
||||
},
|
||||
toggleSharingComments: (status: boolean) => {
|
||||
post.disableSharing = status
|
||||
dispatch(postActions.dbUpdatePost(post, (x: any) => x))
|
||||
dispatch(postActions.dbUpdatePost(post.set('disableSharing', status), (x: any) => x))
|
||||
},
|
||||
goTo: (url: string) => dispatch(push(url)),
|
||||
setHomeTitle: (title: string) => dispatch(globalActions.setHeaderTitle(title || '')),
|
||||
@@ -501,21 +512,21 @@ const mapDispatchToProps = (dispatch: any, ownProps: IPostComponentProps) => {
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IPostComponentProps) => {
|
||||
const { post, vote, authorize, comment } = state
|
||||
const { uid } = authorize
|
||||
let currentUserVote = ownProps.post.votes ? ownProps.post.votes[uid] : false
|
||||
const postModel = post.userPosts[ownProps.post.ownerUserId!][ownProps.post.id!]
|
||||
const postOwner = (post.userPosts[uid] ? Object.keys(post.userPosts[uid]).filter((key) => { return ownProps.post.id === key }).length : 0)
|
||||
const commentList: { [commentId: string]: Comment } = comment.postComments[ownProps.post.id!]
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IPostComponentProps) => {
|
||||
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
let currentUserVote = ownProps.post.getIn(['votes', uid], false)
|
||||
const voteCount = state.getIn(['post', 'userPosts', ownProps.post.get('ownerUserId'), ownProps.post.get('id'), 'score'], 0)
|
||||
const commentList: { [commentId: string]: Comment } = state.getIn(['comment', 'postComments', ownProps.post.get('id')])
|
||||
const user = state.getIn(['user', 'info', ownProps.post.get('ownerUserId')])
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
commentList,
|
||||
avatar: state.user.info && state.user.info[ownProps.post.ownerUserId!] ? state.user.info[ownProps.post.ownerUserId!].avatar || '' : '',
|
||||
fullName: state.user.info && state.user.info[ownProps.post.ownerUserId!] ? state.user.info[ownProps.post.ownerUserId!].fullName || '' : '',
|
||||
voteCount: postModel.score,
|
||||
avatar: user ? user.avatar : '',
|
||||
fullName: user ? user.fullName : '',
|
||||
voteCount,
|
||||
currentUserVote,
|
||||
isPostOwner: postOwner > 0
|
||||
isPostOwner: uid === ownProps.post.get('ownerUserId')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Post } from 'core/domain/posts'
|
||||
|
||||
import {Map} from 'immutable'
|
||||
export interface IPostWriteComponentProps {
|
||||
|
||||
/**
|
||||
@@ -55,7 +55,7 @@ export interface IPostWriteComponentProps {
|
||||
/**
|
||||
* Post model
|
||||
*/
|
||||
postModel?: Post
|
||||
postModel?: Map<string, any>
|
||||
|
||||
/**
|
||||
* Save a post
|
||||
@@ -69,7 +69,7 @@ export interface IPostWriteComponentProps {
|
||||
*
|
||||
* @memberof IPostWriteComponentProps
|
||||
*/
|
||||
update?: (post: Post, callback: Function) => any
|
||||
update?: (post: Map<string, any>, callback: Function) => any
|
||||
|
||||
/**
|
||||
* Styles
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
import { Card, CardActions, CardHeader, CardMedia, CardContent } from 'material-ui'
|
||||
import List, {
|
||||
@@ -108,15 +109,15 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps, IPos
|
||||
/**
|
||||
* Post text
|
||||
*/
|
||||
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '') : '',
|
||||
postText: this.props.edit && postModel ? postModel.get('body', '') : '',
|
||||
/**
|
||||
* The URL image of the post
|
||||
*/
|
||||
image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '') : '',
|
||||
image: this.props.edit && postModel ? postModel.get('image', '') : '',
|
||||
/**
|
||||
* The path identifier of image on the server
|
||||
*/
|
||||
imageFullPath: this.props.edit && postModel ? (postModel.imageFullPath ? postModel.imageFullPath! : '') : '',
|
||||
imageFullPath: this.props.edit && postModel ? postModel.get('imageFullPath', '') : '',
|
||||
/**
|
||||
* If it's true gallery will be open
|
||||
*/
|
||||
@@ -132,11 +133,11 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps, IPos
|
||||
/**
|
||||
* If it's true comment will be disabled on post
|
||||
*/
|
||||
disableComments: this.props.edit && postModel ? postModel.disableComments! : false,
|
||||
disableComments: this.props.edit && postModel ? postModel.get('disableComments') : false,
|
||||
/**
|
||||
* If it's true share will be disabled on post
|
||||
*/
|
||||
disableSharing: this.props.edit && postModel ? postModel.disableSharing! : false
|
||||
disableSharing: this.props.edit && postModel ? postModel.get('disableSharing') : false
|
||||
|
||||
}
|
||||
|
||||
@@ -253,14 +254,14 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps, IPos
|
||||
}, onRequestClose)
|
||||
}
|
||||
} else { // In edit status we pass post to update functions
|
||||
postModel!.body = postText
|
||||
postModel!.tags = tags
|
||||
postModel!.image = image
|
||||
postModel!.imageFullPath = imageFullPath
|
||||
postModel!.disableComments = disableComments
|
||||
postModel!.disableSharing = disableSharing
|
||||
const updatedPost = postModel!.set('body', postText)
|
||||
.set('tags', tags)
|
||||
.set('image', image)
|
||||
.set('imageFullPath', imageFullPath)
|
||||
.set('disableComments', disableComments)
|
||||
.set('disableSharing', disableSharing)
|
||||
|
||||
update!(postModel!, onRequestClose)
|
||||
update!(updatedPost, onRequestClose)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,34 +338,38 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps, IPos
|
||||
if (!nextProps.open) {
|
||||
const { postModel } = this.props
|
||||
this.setState({
|
||||
/**
|
||||
* Post text
|
||||
*/
|
||||
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '') : '',
|
||||
/**
|
||||
* The URL image of the post
|
||||
*/
|
||||
image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '') : '',
|
||||
/**
|
||||
* The path identifier of image on the server
|
||||
*/
|
||||
imageFullPath: this.props.edit && postModel ? (postModel.imageFullPath ? postModel.imageFullPath! : '') : '',
|
||||
/**
|
||||
* If it's true gallery will be open
|
||||
*/
|
||||
galleryOpen: false,
|
||||
/**
|
||||
* If it's true post button will be disabled
|
||||
*/
|
||||
disabledPost: true,
|
||||
/**
|
||||
* If it's true comment will be disabled on post
|
||||
*/
|
||||
disableComments: this.props.edit && postModel ? postModel.disableComments! : false,
|
||||
/**
|
||||
* If it's true share will be disabled on post
|
||||
*/
|
||||
disableSharing: this.props.edit && postModel ? postModel.disableSharing! : false
|
||||
/**
|
||||
* Post text
|
||||
*/
|
||||
postText: this.props.edit && postModel ? postModel.get('body', '') : '',
|
||||
/**
|
||||
* The URL image of the post
|
||||
*/
|
||||
image: this.props.edit && postModel ? postModel.get('image', '') : '',
|
||||
/**
|
||||
* The path identifier of image on the server
|
||||
*/
|
||||
imageFullPath: this.props.edit && postModel ? postModel.get('imageFullPath', '') : '',
|
||||
/**
|
||||
* If it's true gallery will be open
|
||||
*/
|
||||
galleryOpen: false,
|
||||
/**
|
||||
* Whether menu is open
|
||||
*/
|
||||
menuOpen: false,
|
||||
/**
|
||||
* If it's true post button will be disabled
|
||||
*/
|
||||
disabledPost: true,
|
||||
/**
|
||||
* If it's true comment will be disabled on post
|
||||
*/
|
||||
disableComments: this.props.edit && postModel ? postModel.get('disableComments') : false,
|
||||
/**
|
||||
* If it's true share will be disabled on post
|
||||
*/
|
||||
disableSharing: this.props.edit && postModel ? postModel.get('disableSharing') : false
|
||||
|
||||
})
|
||||
}
|
||||
@@ -576,7 +581,7 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps, IPos
|
||||
const mapDispatchToProps = (dispatch: any, ownProps: IPostWriteComponentProps) => {
|
||||
return {
|
||||
post: (post: Post, callBack: Function) => dispatch(postActions.dbAddImagePost(post, callBack)),
|
||||
update: (post: Post, callBack: Function) => dispatch(postActions.dbUpdatePost(post, callBack))
|
||||
update: (post: Map<string, any>, callBack: Function) => dispatch(postActions.dbUpdatePost(post, callBack))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,12 +591,14 @@ const mapDispatchToProps = (dispatch: any, ownProps: IPostWriteComponentProps) =
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IPostWriteComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IPostWriteComponentProps) => {
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
const user = state.getIn(['user', 'info', uid], {})
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
postImageState: state.imageGallery.status,
|
||||
ownerAvatar: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].avatar : '',
|
||||
ownerDisplayName: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].fullName : ''
|
||||
translate: getTranslate(state.get('locale')),
|
||||
postImageState: state.getIn(['imageGallery', 'status']),
|
||||
ownerAvatar: user.avatar || '',
|
||||
ownerDisplayName: user.fullName || ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// - Import react components
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import config from 'src/config'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Material UI
|
||||
import { grey } from 'material-ui/colors'
|
||||
@@ -33,39 +33,6 @@ import { IProfileHeaderComponentState } from './IProfileHeaderComponentState'
|
||||
*/
|
||||
export class ProfileHeaderComponent extends Component<IProfileHeaderComponentProps, IProfileHeaderComponentState> {
|
||||
|
||||
static propTypes = {
|
||||
|
||||
/**
|
||||
* User avatar address
|
||||
*/
|
||||
avatar: PropTypes.string,
|
||||
/**
|
||||
* User banner address
|
||||
*/
|
||||
banner: PropTypes.string,
|
||||
/**
|
||||
* User tagline
|
||||
*/
|
||||
tagLine: PropTypes.string,
|
||||
/**
|
||||
* User full name
|
||||
*/
|
||||
fullName: PropTypes.string.isRequired,
|
||||
/**
|
||||
* The number of followers
|
||||
*/
|
||||
followerCount: PropTypes.number,
|
||||
/**
|
||||
* User identifier
|
||||
*/
|
||||
userId: PropTypes.string,
|
||||
/**
|
||||
* If the user profile identifier of param is equal to the user authed identifier
|
||||
*/
|
||||
isAuthedUser: PropTypes.bool
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Component constructor
|
||||
* @param {object} props is an object properties of component
|
||||
@@ -186,7 +153,7 @@ export class ProfileHeaderComponent extends Component<IProfileHeaderComponentPro
|
||||
/>
|
||||
<div className='left'>
|
||||
{/* User avatar*/}
|
||||
<div style={{ display: 'flex', justifyContent: 'center' }}><UserAvatar fullName={this.props.fullName} fileName={this.props.avatar} size={60} style={styles.avatar} /></div>
|
||||
<div style={{ display: 'flex', justifyContent: 'center' }}><UserAvatar fullName={this.props.fullName || ' '} fileName={this.props.avatar} size={60} style={styles.avatar} /></div>
|
||||
<div className='info'>
|
||||
<div className='fullName'>
|
||||
{this.props.fullName}
|
||||
@@ -235,11 +202,11 @@ const mapDispatchToProps = (dispatch: any, ownProps: IProfileHeaderComponentProp
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IProfileHeaderComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IProfileHeaderComponentProps) => {
|
||||
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
editProfileOpen: state.user.openEditProfile
|
||||
translate: getTranslate(state.get('locale')),
|
||||
editProfileOpen: state.getIn(['user', 'openEditProfile'])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Feed } from 'core/domain/common/feed'
|
||||
import { ServerRequestModel } from 'models/server/serverRequestModel'
|
||||
import { Profile } from 'core/domain/users'
|
||||
import { ServerRequestStatusType } from 'store/actions/serverRequestStatusType'
|
||||
|
||||
export interface ISendFeedbackComponentProps {
|
||||
/**
|
||||
@@ -21,7 +22,7 @@ export interface ISendFeedbackComponentProps {
|
||||
/**
|
||||
* The server request of send feedback
|
||||
*/
|
||||
sendFeedbackRequest?: ServerRequestModel
|
||||
sendFeedbackRequestType?: ServerRequestStatusType
|
||||
|
||||
/**
|
||||
* Current user profile
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import classNames from 'classnames'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Material UI
|
||||
import Paper from 'material-ui/Paper'
|
||||
@@ -89,7 +90,7 @@ export class SendFeedbackComponent extends Component<ISendFeedbackComponentProps
|
||||
}
|
||||
|
||||
mainForm = () => {
|
||||
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest, translate } = this.props
|
||||
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequestType, translate } = this.props
|
||||
const { feedText } = this.state
|
||||
return (
|
||||
<div className='main-box'>
|
||||
@@ -168,11 +169,11 @@ export class SendFeedbackComponent extends Component<ISendFeedbackComponentProps
|
||||
}
|
||||
|
||||
getFeedbackForm = () => {
|
||||
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest } = this.props
|
||||
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequestType } = this.props
|
||||
const { feedText } = this.state
|
||||
|
||||
if (sendFeedbackRequest) {
|
||||
switch (sendFeedbackRequest.status) {
|
||||
if (sendFeedbackRequestType) {
|
||||
switch (sendFeedbackRequestType) {
|
||||
case ServerRequestStatusType.Sent:
|
||||
return this.loadingForm()
|
||||
|
||||
@@ -195,7 +196,7 @@ export class SendFeedbackComponent extends Component<ISendFeedbackComponentProps
|
||||
* @return {react element} return the DOM which rendered by component
|
||||
*/
|
||||
render () {
|
||||
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest, classes } = this.props
|
||||
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequestType, classes } = this.props
|
||||
const { feedText } = this.state
|
||||
|
||||
return (
|
||||
@@ -237,19 +238,19 @@ const mapDispatchToProps = (dispatch: Function, ownProps: ISendFeedbackComponent
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: ISendFeedbackComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: ISendFeedbackComponentProps) => {
|
||||
|
||||
const { server, global, authorize, user } = state
|
||||
const { request } = server
|
||||
const { uid } = authorize
|
||||
const currentUser: User = user.info && user.info[uid] ? { ...user.info[uid], userId: uid } : {}
|
||||
const { sendFeedbackStatus } = global
|
||||
const sendFeedbackRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CommonSendFeedback, uid)] : null
|
||||
const request = state.getIn(['server', 'request'])
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
const requestId = StringAPI.createServerRequestId(ServerRequestType.CommonSendFeedback, uid)
|
||||
const currentUser: User = { ...state.getIn(['user', 'info', uid], {}), userId: uid }
|
||||
const sendFeedbackStatus = state.getIn(['global', 'sendFeedbackStatus'])
|
||||
const sendFeedbackRequestType = state.getIn(['server', 'request', requestId])
|
||||
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
sendFeedbackStatus,
|
||||
sendFeedbackRequest,
|
||||
sendFeedbackRequestType: sendFeedbackRequestType ? sendFeedbackRequestType.status : ServerRequestStatusType.NoAction,
|
||||
currentUser
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Post } from 'core/domain/posts'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
export interface IShareDialogComponentProps {
|
||||
|
||||
@@ -25,7 +26,7 @@ export interface IShareDialogComponentProps {
|
||||
/**
|
||||
* The post object for sharing
|
||||
*/
|
||||
post: Post
|
||||
post: Map<string, any>
|
||||
|
||||
/**
|
||||
* Styles
|
||||
|
||||
@@ -105,9 +105,9 @@ export class ShareDialogComponent extends Component<IShareDialogComponentProps,
|
||||
<div>
|
||||
<FacebookShareButton
|
||||
onShareWindowClose={onClose}
|
||||
url={`${location.origin}/${post.ownerUserId}/posts/${post.id}`}
|
||||
quote={post.body}
|
||||
hashtag={`#${post.tags![0]}`}>
|
||||
url={`${location.origin}/${post.get('ownerUserId')}/posts/${post.get('id')}`}
|
||||
quote={post.get('body')}
|
||||
hashtag={`#${post.getIn(['tags', 0], '')}`}>
|
||||
<MenuItem >
|
||||
<ListItemIcon classes={{ root: classes.networkShare }}>
|
||||
<FacebookIcon
|
||||
@@ -121,9 +121,9 @@ export class ShareDialogComponent extends Component<IShareDialogComponentProps,
|
||||
<div>
|
||||
<TwitterShareButton
|
||||
onShareWindowClose={onClose}
|
||||
url={`${location.origin}/${post.ownerUserId}/posts/${post.id}`}
|
||||
quote={post.body}
|
||||
hashtag={`#${post.tags![0]}`}>
|
||||
url={`${location.origin}/${post.get('ownerUserId')}/posts/${post.get('id')}`}
|
||||
quote={post.get('body')}
|
||||
hashtag={`#${post.getIn(['tags', 0], '')}`}>
|
||||
<MenuItem >
|
||||
<ListItemIcon classes={{ root: classes.networkShare }}>
|
||||
<TwitterIcon
|
||||
@@ -137,9 +137,9 @@ export class ShareDialogComponent extends Component<IShareDialogComponentProps,
|
||||
<div>
|
||||
<LinkedinShareButton
|
||||
onShareWindowClose={onClose}
|
||||
url={`${location.origin}/${post.ownerUserId}/posts/${post.id}`}
|
||||
quote={post.body}
|
||||
hashtag={`#${post.tags![0]}`}>
|
||||
url={`${location.origin}/${post.get('ownerUserId')}/posts/${post.get('id')}`}
|
||||
quote={post.get('body')}
|
||||
hashtag={`#${post.getIn(['tags', 0], '')}`}>
|
||||
<MenuItem >
|
||||
<ListItemIcon classes={{ root: classes.networkShare }}>
|
||||
<LinkedinIcon
|
||||
@@ -153,9 +153,9 @@ export class ShareDialogComponent extends Component<IShareDialogComponentProps,
|
||||
<div>
|
||||
<GooglePlusShareButton
|
||||
onShareWindowClose={onClose}
|
||||
url={`${location.origin}/${post.ownerUserId}/posts/${post.id}`}
|
||||
quote={post.body}
|
||||
hashtag={`#${post.tags![0]}`}>
|
||||
url={`${location.origin}/${post.get('ownerUserId')}/posts/${post.get('id')}`}
|
||||
quote={post.get('body')}
|
||||
hashtag={`#${post.getIn(['tags', 0], '')}`}>
|
||||
<MenuItem >
|
||||
<ListItemIcon classes={{ root: classes.networkShare }}>
|
||||
<GooglePlusIcon
|
||||
@@ -174,7 +174,7 @@ export class ShareDialogComponent extends Component<IShareDialogComponentProps,
|
||||
</MenuItem>
|
||||
</MenuList>)
|
||||
: <div>
|
||||
<TextField autoFocus fullWidth={true} id='text-field-default' defaultValue={`${location.origin}/${post.ownerUserId}/posts/${post.id}`} />
|
||||
<TextField autoFocus fullWidth={true} id='text-field-default' defaultValue={`${location.origin}/${post.get('ownerUserId')}/posts/${post.get('id')}`} />
|
||||
<Typography className={classNames('animate-top', classes.clipboard)} variant='headline' component='h2'>
|
||||
Link has been copied to clipboard ...
|
||||
</Typography>
|
||||
@@ -205,7 +205,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: IShareDialogComponentProps)
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IShareDialogComponentProps) => {
|
||||
return {
|
||||
translate: getTranslate(state.locale)
|
||||
translate: getTranslate(state.get('locale'))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import Avatar from 'material-ui/Avatar'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
|
||||
@@ -95,8 +96,8 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IUserAvatarComponentPr
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IUserAvatarComponentProps) => {
|
||||
return {
|
||||
avatarURL: state.imageGallery.imageURLList,
|
||||
imageRequests: state.imageGallery.imageRequests
|
||||
avatarURL: state.getIn(['imageGallery', 'imageURLList']),
|
||||
imageRequests: state.getIn(['imageGallery', 'imageRequests'])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,40 +3,28 @@ import { Circle } from 'core/domain/circles/circle'
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
import { ServerRequestStatusType } from 'store/actions/serverRequestStatusType'
|
||||
import { ServerRequestModel } from 'models/server/serverRequestModel'
|
||||
|
||||
import {Map, List} from 'immutable'
|
||||
export interface IUserBoxComponentProps {
|
||||
|
||||
/**
|
||||
* User identifier
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
userId: string
|
||||
|
||||
/**
|
||||
* User
|
||||
*
|
||||
* @type {User}
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
user: UserTie
|
||||
|
||||
/**
|
||||
* Circles
|
||||
*
|
||||
* @type {{[circleId: string]: Circle}}
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
circles?: {[circleId: string]: Circle}
|
||||
circles?: Map<string, Map<string, any>>
|
||||
|
||||
/**
|
||||
* List of circles' id
|
||||
*
|
||||
* @type {string[]}
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
userBelongCircles?: string[]
|
||||
userBelongCircles?: List<string>
|
||||
|
||||
/**
|
||||
* Whether current user followed this user
|
||||
@@ -45,54 +33,38 @@ export interface IUserBoxComponentProps {
|
||||
|
||||
/**
|
||||
* The number of circles
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
belongCirclesCount?: number
|
||||
|
||||
/**
|
||||
* The first circle
|
||||
*
|
||||
* @type {User}
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
firstBelongCircle?: Circle
|
||||
firstBelongCircle?: Map<string, any>
|
||||
|
||||
/**
|
||||
* Avatar address
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
avatar?: string
|
||||
|
||||
/**
|
||||
* User full name
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
fullName?: string
|
||||
|
||||
/**
|
||||
* The `Following` circle identifier of current user
|
||||
*/
|
||||
followingCircleId?: string
|
||||
followingCircle?: Map<string, any>
|
||||
|
||||
/**
|
||||
* Create a circle
|
||||
*
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
createCircle?: (name: string) => any
|
||||
|
||||
/**
|
||||
* Add a user in a circle
|
||||
*
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
addUserToCircle?: (circleIds: string[],user: UserTie) => any
|
||||
addUserToCircle?: (circleIds: List<string>,user: UserTie) => any
|
||||
|
||||
/**
|
||||
* Add referer user to the `Following` circle of current user
|
||||
@@ -107,12 +79,12 @@ export interface IUserBoxComponentProps {
|
||||
/**
|
||||
* Set current user selected circles for referer user
|
||||
*/
|
||||
setSelectedCircles?: (userId: string, circleList: string[]) => any
|
||||
setSelectedCircles?: (userId: string, circleList: List<string>) => any
|
||||
|
||||
/**
|
||||
* Remove current user selected circles for referer user
|
||||
*/
|
||||
removeSelectedCircles?: (userId: string, circleList: string[]) => any
|
||||
removeSelectedCircles?: (userId: string, circleList: List<string>) => any
|
||||
|
||||
/**
|
||||
* Open select circle box
|
||||
@@ -126,8 +98,6 @@ export interface IUserBoxComponentProps {
|
||||
|
||||
/**
|
||||
* Redirect page to [url]
|
||||
*
|
||||
* @memberof IUserBoxComponentProps
|
||||
*/
|
||||
goTo?: (url: string) => any
|
||||
|
||||
@@ -149,7 +119,7 @@ export interface IUserBoxComponentProps {
|
||||
/**
|
||||
* Keep selected circles for refere user
|
||||
*/
|
||||
selectedCircles?: string[]
|
||||
selectedCircles?: List<string>
|
||||
|
||||
/**
|
||||
* Whether the select circles box for referer user is open
|
||||
|
||||
@@ -6,6 +6,7 @@ import PropTypes from 'prop-types'
|
||||
import { push } from 'react-router-redux'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import classNames from 'classnames'
|
||||
import {Map, List as ImuList} from 'immutable'
|
||||
|
||||
// - Material UI
|
||||
import Paper from 'material-ui/Paper'
|
||||
@@ -112,7 +113,6 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
borderRadius: '4px'
|
||||
}
|
||||
}
|
||||
selectedCircles: string[]
|
||||
|
||||
/**
|
||||
* Component constructor
|
||||
@@ -140,7 +140,6 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
*/
|
||||
disabledDoneCircles: true
|
||||
}
|
||||
this.selectedCircles = userBelongCircles!.slice()
|
||||
// Binding functions to `this`
|
||||
this.handleChangeName = this.handleChangeName.bind(this)
|
||||
this.onCreateCircle = this.onCreateCircle.bind(this)
|
||||
@@ -153,11 +152,10 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
* Handle follow user
|
||||
*/
|
||||
handleDoneAddCircle = () => {
|
||||
const { userId, user, addUserToCircle, selectedCircles, deleteFollowingUser } = this.props
|
||||
const { avatar, fullName } = user
|
||||
const { userId, user, addUserToCircle, selectedCircles, deleteFollowingUser, avatar, fullName } = this.props
|
||||
const { disabledDoneCircles } = this.state
|
||||
if (!disabledDoneCircles) {
|
||||
if (selectedCircles!.length > 0) {
|
||||
if (selectedCircles!.count() > 0) {
|
||||
addUserToCircle!(selectedCircles!, { avatar, userId, fullName })
|
||||
} else {
|
||||
deleteFollowingUser!(userId)
|
||||
@@ -171,14 +169,13 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
onFollowUser = (event: any) => {
|
||||
// This prevents ghost click
|
||||
event.preventDefault()
|
||||
const { isFollowed, followUser, followingCircleId, userId, user, followRequest } = this.props
|
||||
const { isFollowed, followUser, followingCircle, userId, user, followRequest, avatar, fullName } = this.props
|
||||
|
||||
if (followRequest && followRequest.status === ServerRequestStatusType.Sent) {
|
||||
return
|
||||
}
|
||||
const { avatar, fullName } = user
|
||||
if (!isFollowed) {
|
||||
followUser!(followingCircleId!, { avatar, userId, fullName })
|
||||
followUser!(followingCircle!.get('id'), { avatar, userId, fullName })
|
||||
} else {
|
||||
this.onRequestOpenAddCircle()
|
||||
}
|
||||
@@ -234,17 +231,13 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
|
||||
handleSelectCircle = (event: object, isInputChecked: boolean, circleId: string) => {
|
||||
const { userBelongCircles, circles, setSelectedCircles, selectedCircles, userId } = this.props
|
||||
let newSelectedCircles = selectedCircles!.slice()
|
||||
let newSelectedCircles = selectedCircles!
|
||||
if (isInputChecked) {
|
||||
|
||||
newSelectedCircles = [
|
||||
...selectedCircles!,
|
||||
circleId
|
||||
]
|
||||
newSelectedCircles = selectedCircles!.push(circleId)
|
||||
|
||||
} else {
|
||||
const circleIndex = selectedCircles!.indexOf(circleId)
|
||||
newSelectedCircles.splice(circleIndex, 1)
|
||||
newSelectedCircles = newSelectedCircles.remove(circleIndex)
|
||||
}
|
||||
|
||||
setSelectedCircles!(userId, newSelectedCircles)
|
||||
@@ -258,39 +251,39 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
*/
|
||||
circleList = () => {
|
||||
let { circles, userId, userBelongCircles, selectedCircles, classes } = this.props
|
||||
|
||||
const circleDomList: any[] = []
|
||||
if (circles) {
|
||||
|
||||
const parsedDate = Object.keys(circles).map((circleId, index) => {
|
||||
let isBelong = selectedCircles ? selectedCircles!.indexOf(circleId) > -1 : false
|
||||
circles.forEach((circle, circleId) => {
|
||||
let isBelong = selectedCircles ? selectedCircles!.indexOf(circleId!) > -1 : false
|
||||
|
||||
// Create checkbox for selected/unselected circle
|
||||
return (
|
||||
circleDomList.push(
|
||||
<ListItem key={`${circleId}-${userId}`} dense className={classes.listItem}>
|
||||
<ListItemText className={classes.circleName} primary={circles![circleId].name} />
|
||||
<ListItemText className={classes.circleName} primary={circle!.get('name')} />
|
||||
<ListItemSecondaryAction>
|
||||
<Checkbox
|
||||
onChange={(event: object, isInputChecked: boolean) => this.handleSelectCircle(event, isInputChecked, circleId)}
|
||||
onChange={(event: object, isInputChecked: boolean) => this.handleSelectCircle(event, isInputChecked, circleId!)}
|
||||
checked={isBelong}
|
||||
/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>)
|
||||
})
|
||||
|
||||
return parsedDate
|
||||
return circleDomList
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the the selected circles changed
|
||||
*/
|
||||
selectedCircleChange = (selectedCircles: string[]) => {
|
||||
selectedCircleChange = (selectedCircles: ImuList<string>) => {
|
||||
let isChanged = false
|
||||
const { userBelongCircles, circles } = this.props
|
||||
|
||||
if (selectedCircles.length === userBelongCircles!.length) {
|
||||
for (let circleIndex: number = 0; circleIndex < selectedCircles.length; circleIndex++) {
|
||||
const selectedCircleId = selectedCircles[circleIndex]
|
||||
if (selectedCircles.count() === userBelongCircles!.count()) {
|
||||
for (let circleIndex: number = 0; circleIndex < selectedCircles.count(); circleIndex++) {
|
||||
const selectedCircleId = selectedCircles.get(circleIndex)
|
||||
if (!(userBelongCircles!.indexOf(selectedCircleId) > -1)) {
|
||||
isChanged = true
|
||||
break
|
||||
@@ -308,7 +301,18 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
*/
|
||||
render () {
|
||||
const { disabledDoneCircles } = this.state
|
||||
const { isFollowed, followRequest, userId, isSelecteCirclesOpen, addToCircleRequest, deleteFollowingUserRequest, classes, translate } = this.props
|
||||
const {
|
||||
isFollowed,
|
||||
firstBelongCircle,
|
||||
belongCirclesCount,
|
||||
followRequest,
|
||||
userId,
|
||||
isSelecteCirclesOpen,
|
||||
addToCircleRequest,
|
||||
deleteFollowingUserRequest,
|
||||
classes,
|
||||
translate
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<Paper key={userId} elevation={1} className={classNames('grid-cell', classes.paper)}>
|
||||
@@ -331,7 +335,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
</div>
|
||||
<div onClick={() => this.props.goTo!(`/${this.props.userId}`)} className='people__name' style={{ cursor: 'pointer' }}>
|
||||
<div>
|
||||
{this.props.user.fullName}
|
||||
{this.props.fullName}
|
||||
</div>
|
||||
</div>
|
||||
<div style={this.styles.followButton as any}>
|
||||
@@ -344,7 +348,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
}
|
||||
>
|
||||
{!isFollowed ? translate!('userBox.followButton')
|
||||
: (this.props.belongCirclesCount! > 1 ? translate!('userBox.numberOfCircleButton', {circlesCount: this.props.belongCirclesCount}) : ((this.props.firstBelongCircle) ? this.props.firstBelongCircle.name : translate!('userBox.followButton')))}
|
||||
: (belongCirclesCount! > 1 ? translate!('userBox.numberOfCircleButton', {circlesCount: belongCirclesCount}) : ((firstBelongCircle) ? firstBelongCircle.get('name', 'Followed') : translate!('userBox.followButton')))}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -414,7 +418,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
||||
const mapDispatchToProps = (dispatch: Function, ownProps: IUserBoxComponentProps) => {
|
||||
return {
|
||||
createCircle: (name: string) => dispatch(circleActions.dbAddCircle(name)),
|
||||
addUserToCircle: (circleIds: string[], user: UserTie) => dispatch(circleActions.dbUpdateUserInCircles(circleIds, user)),
|
||||
addUserToCircle: (circleIds: ImuList<string>, user: UserTie) => dispatch(circleActions.dbUpdateUserInCircles(circleIds, user)),
|
||||
followUser: (circleId: string, userFollowing: UserTie) => dispatch(circleActions.dbFollowUser(circleId, userFollowing)),
|
||||
deleteFollowingUser: (followingId: string) => dispatch(circleActions.dbDeleteFollowingUser(followingId)),
|
||||
setSelectedCircles: (userId: string, circleList: string[]) => dispatch(circleActions.setSelectedCircles(userId, circleList)),
|
||||
@@ -432,36 +436,41 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IUserBoxComponentProps
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IUserBoxComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IUserBoxComponentProps) => {
|
||||
|
||||
const { circle, authorize, server } = state
|
||||
const { uid } = authorize
|
||||
const { request } = server
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
const request = state.getIn(['server', 'request'])
|
||||
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
const userBelongCircles = circle ? (circle.userTies[ownProps.userId] ? circle.userTies[ownProps.userId].circleIdList : []) : []
|
||||
const isFollowed = userBelongCircles.length > 0
|
||||
const followingCircleId = circles ? Object.keys(circles)
|
||||
.filter((circleId) => circles[circleId].isSystem && circles[circleId].name === `Following`)[0] : ''
|
||||
const followRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleFollowUser, ownProps.userId)] : null
|
||||
const addToCircleRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleAddToCircle, ownProps.userId)] : null
|
||||
const deleteFollowingUserRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleDeleteFollowingUser, ownProps.userId)] : null
|
||||
const selectedCircles = circle.selectedCircles ? circle.selectedCircles[ownProps.userId] : []
|
||||
const isSelecteCirclesOpen = circle.openSelecteCircles ? circle.openSelecteCircles[ownProps.userId] : []
|
||||
const circles: Map<string, Map<string, any>> = state.getIn(['circle', 'circleList'], {})
|
||||
const userBelongCircles: ImuList<any> = state.getIn(['circle', 'userTies', ownProps.userId, 'circleIdList'], ImuList())
|
||||
const isFollowed = userBelongCircles.count() > 0
|
||||
const followingCircle = circles
|
||||
.filter((followingCircle) => followingCircle!.get('isSystem', false) && followingCircle!.get('name') === `Following`)
|
||||
.toArray()[0]
|
||||
const followRequestId = StringAPI.createServerRequestId(ServerRequestType.CircleFollowUser, ownProps.userId)
|
||||
const followRequest = state.getIn(['server', 'request', followRequestId])
|
||||
const addToCircleRequestId = StringAPI.createServerRequestId(ServerRequestType.CircleAddToCircle, ownProps.userId)
|
||||
const addToCircleRequest = state.getIn(['server', 'request', addToCircleRequestId])
|
||||
const deleteFollowingUserRequestId = StringAPI.createServerRequestId(ServerRequestType.CircleDeleteFollowingUser, ownProps.userId)
|
||||
const deleteFollowingUserRequest = state.getIn(['server', 'request', deleteFollowingUserRequestId])
|
||||
const selectedCircles = state.getIn(['circle', 'selectedCircles', ownProps.userId], [])
|
||||
|
||||
const isSelecteCirclesOpen = state.getIn(['circle', 'openSelecteCircles', ownProps.userId], [])
|
||||
const userBox = state.getIn(['user', 'info', ownProps.userId])
|
||||
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
isSelecteCirclesOpen,
|
||||
isFollowed,
|
||||
selectedCircles,
|
||||
circles,
|
||||
followingCircleId,
|
||||
followingCircle,
|
||||
userBelongCircles,
|
||||
followRequest,
|
||||
belongCirclesCount: userBelongCircles.length || 0,
|
||||
firstBelongCircle: userBelongCircles ? (circles ? circles[userBelongCircles[0]] : {}) : {},
|
||||
avatar: state.user.info && state.user.info[ownProps.userId] ? state.user.info[ownProps.userId].avatar || '' : '',
|
||||
fullName: state.user.info && state.user.info[ownProps.userId] ? state.user.info[ownProps.userId].fullName || '' : ''
|
||||
belongCirclesCount: userBelongCircles.count() || 0,
|
||||
firstBelongCircle: userBelongCircles ? circles.get(userBelongCircles.get(0), Map({})) : Map({}),
|
||||
avatar: userBox.avatar || '' ,
|
||||
fullName: userBox.fullName || ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { User } from 'core/domain/users'
|
||||
import { UserTie } from 'core/domain/circles'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
export interface IUserBoxListComponentProps {
|
||||
|
||||
@@ -9,7 +10,7 @@ export interface IUserBoxListComponentProps {
|
||||
* @type {{[userId: string]: User}}
|
||||
* @memberof IUserBoxListComponentProps
|
||||
*/
|
||||
users: {[userId: string]: UserTie}
|
||||
users: Map<string, UserTie>
|
||||
|
||||
/**
|
||||
* User identifier
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
import UserBox from 'components/userBox'
|
||||
|
||||
import { IUserBoxListComponentProps } from './IUserBoxListComponentProps'
|
||||
import { IUserBoxListComponentState } from './IUserBoxListComponentState'
|
||||
import { UserTie } from 'core/domain/circles/userTie'
|
||||
|
||||
// - Import API
|
||||
|
||||
@@ -42,15 +44,17 @@ export class UserBoxListComponent extends Component<IUserBoxListComponentProps,I
|
||||
}
|
||||
|
||||
userList = () => {
|
||||
let { users, uid } = this.props
|
||||
|
||||
let { uid } = this.props
|
||||
const users = this.props.users
|
||||
const userBoxList: any[] = []
|
||||
if (users) {
|
||||
return Object.keys(users).map((key, index) => {
|
||||
users.forEach((user: UserTie, key: string) => {
|
||||
if (uid !== key) {
|
||||
return <UserBox key={key} userId={key} user={users[key]}/>
|
||||
userBoxList.push(<UserBox key={key} userId={key} user={user}/>)
|
||||
}
|
||||
})
|
||||
}
|
||||
return userBoxList
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +96,7 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IUserBoxListComponentP
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IUserBoxListComponentProps) => {
|
||||
const {uid} = state.authorize
|
||||
const uid = state.getIn(['authorize', 'uid'], 0)
|
||||
return {
|
||||
uid
|
||||
}
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import { Circle } from 'core/domain/circles'
|
||||
|
||||
import {Map} from 'immutable'
|
||||
export interface IYourCirclesComponentProps {
|
||||
|
||||
/**
|
||||
* Circles
|
||||
*
|
||||
* @type {{[circleId: string]: Circle}}
|
||||
* @memberof IYourCirclesComponentProps
|
||||
*/
|
||||
circles?: {[circleId: string]: Circle}
|
||||
circles?: Map<string, Map<string, any>>
|
||||
|
||||
/**
|
||||
* User identifier
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof IYourCirclesComponentProps
|
||||
*/
|
||||
uid?: string
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
import List from 'material-ui/List'
|
||||
|
||||
// - Import app components
|
||||
@@ -44,8 +46,8 @@ export class YourCirclesComponent extends Component<IYourCirclesComponentProps,I
|
||||
let parsedCircles: any[] = []
|
||||
|
||||
if (circles) {
|
||||
Object.keys(circles).map((key, index) => {
|
||||
parsedCircles.push(<CircleComponent key={key} circle={circles![key]} id={key} uid={uid!} />)
|
||||
circles.map((circle, key) => {
|
||||
parsedCircles.push(<CircleComponent key={key} circle={circle!} id={key!} uid={uid!} />)
|
||||
})
|
||||
}
|
||||
return parsedCircles
|
||||
@@ -95,10 +97,9 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IYourCirclesComponentP
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IYourCirclesComponentProps) => {
|
||||
const {circle, authorize, server} = state
|
||||
const { uid } = state.authorize
|
||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IYourCirclesComponentProps) => {
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
const circles: Map<string, Map<string, any>> = state.getIn(['circle', 'circleList'], {})
|
||||
return {
|
||||
uid,
|
||||
circles
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
ADD_VIDEO_POST = 'ADD_VIDEO_POST',
|
||||
ADD_POST = 'ADD_POST',
|
||||
UPDATE_POST = 'UPDATE_POST',
|
||||
UPDATE_POST_COMMENTS = 'UPDATE_POST_COMMENTS',
|
||||
UPDATE_POST_VOTES = 'UPDATE_POST_VOTES',
|
||||
DELETE_POST = 'DELETE_POST',
|
||||
ADD_LIST_POST = 'ADD_LIST_POST',
|
||||
CLEAR_ALL_DATA_POST = 'CLEAR_ALL_DATA_POST'
|
||||
|
||||
@@ -144,7 +144,7 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IEmailVerificationComp
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IEmailVerificationComponentProps) => {
|
||||
return {
|
||||
translate: getTranslate(state.locale)
|
||||
translate: getTranslate(state.get('locale'))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// - Import react components
|
||||
import { HomeRouter } from 'routes'
|
||||
import { Map } from 'immutable'
|
||||
import React, { Component } from 'react'
|
||||
import _ from 'lodash'
|
||||
import { Route, Switch, withRouter, Redirect, NavLink } from 'react-router-dom'
|
||||
@@ -172,7 +173,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
if (!isVerifide) {
|
||||
goTo!('/emailVerification')
|
||||
|
||||
} else if (!global.defaultLoadDataStatus) {
|
||||
} else if (!global.get('defaultLoadDataStatus')) {
|
||||
|
||||
clearData!()
|
||||
loadData!()
|
||||
@@ -188,7 +189,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
||||
* @memberof Home
|
||||
*/
|
||||
render() {
|
||||
const HR = HomeRouter as any
|
||||
const HR = HomeRouter
|
||||
const { loaded, authed, loadDataStream, mergedPosts, hasMorePosts, showSendFeedback, translate, classes, theme } = this.props
|
||||
const { drawerOpen } = this.state
|
||||
const drawer = (
|
||||
@@ -337,29 +338,28 @@ const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IHomeComponentProps) => {
|
||||
const { authorize, global, user, post, imageGallery, notify, circle } = state
|
||||
const { uid } = authorize
|
||||
let mergedPosts = {}
|
||||
const circles = circle ? (circle.circleList || {}) : {}
|
||||
const followingUsers = circle ? circle.userTies : {}
|
||||
const posts = post.userPosts ? post.userPosts[authorize.uid] : {}
|
||||
const hasMorePosts = post.stream.hasMoreData
|
||||
Object.keys(followingUsers).forEach((userId) => {
|
||||
let newPosts = post.userPosts ? post.userPosts[userId] : {}
|
||||
_.merge(mergedPosts, newPosts)
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IHomeComponentProps) => {
|
||||
const uid = state.getIn(['authorize', 'uid'], {})
|
||||
const global = state.get('global', {})
|
||||
let mergedPosts = Map({})
|
||||
const circles = state.getIn(['circle', 'circleList'], {})
|
||||
const followingUsers: Map<string, any> = state.getIn(['circle', 'userTies'], {})
|
||||
const posts = state.getIn(['post', 'userPosts', uid ], {})
|
||||
const hasMorePosts = state.getIn(['post', 'stream', 'hasMoreData' ], true)
|
||||
followingUsers.forEach((user, userId) => {
|
||||
let newPosts = state.getIn(['post', 'userPosts', userId], {})
|
||||
mergedPosts = mergedPosts.merge(newPosts)
|
||||
})
|
||||
_.merge(mergedPosts, posts)
|
||||
mergedPosts = mergedPosts.merge(posts)
|
||||
return {
|
||||
authed: authorize.authed,
|
||||
isVerifide: authorize.isVerifide,
|
||||
mainStyle: global.sidebarMainStyle,
|
||||
translate: getTranslate(state.locale),
|
||||
currentLanguage: getActiveLanguage(state.locale).code,
|
||||
authed: state.getIn(['authorize', 'authed'], false),
|
||||
isVerifide: state.getIn(['authorize', 'isVerifide'], false),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
currentLanguage: getActiveLanguage(state.get('locale')).code,
|
||||
mergedPosts,
|
||||
global,
|
||||
hasMorePosts,
|
||||
loaded: user.loaded && imageGallery.loaded && notify.loaded && circle.loaded
|
||||
loaded: state.getIn(['user', 'loaded']) && state.getIn(['imageGallery', 'loaded']) && state.getIn(['notify', 'loaded']) && state.getIn(['circle', 'loaded'])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import Divider from 'material-ui/Divider'
|
||||
import ActionAndroid from 'material-ui-icons/Android'
|
||||
import { withStyles } from 'material-ui/styles'
|
||||
import config from 'src/config'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import { localize } from 'react-localize-redux'
|
||||
|
||||
// - Import actions
|
||||
import * as authorizeActions from 'src/store/actions/authorizeActions'
|
||||
@@ -20,6 +20,7 @@ import { ILoginComponentProps } from './ILoginComponentProps'
|
||||
import { ILoginComponentState } from './ILoginComponentState'
|
||||
import { OAuthType } from 'src/core/domain/authorize'
|
||||
import Grid from 'material-ui/Grid/Grid'
|
||||
import CommonAPI from 'api/CommonAPI'
|
||||
|
||||
const styles = (theme: any) => ({
|
||||
textField: {
|
||||
@@ -253,9 +254,8 @@ const mapDispatchToProps = (dispatch: any, ownProps: ILoginComponentProps) => {
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: ILoginComponentProps) => {
|
||||
return {
|
||||
translate: getTranslate(state.locale)
|
||||
}
|
||||
}
|
||||
|
||||
// - Connect component to redux store
|
||||
export default withRouter<any>(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(LoginComponent as any) as any)) as typeof LoginComponent
|
||||
export default withRouter<any>(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(localize(LoginComponent, 'locale', CommonAPI.getStateSlice) as any) as any)) as typeof LoginComponent
|
||||
|
||||
@@ -6,6 +6,8 @@ import { Route, Switch, NavLink, withRouter, Redirect } from 'react-router-dom'
|
||||
import { push } from 'react-router-redux'
|
||||
import Snackbar from 'material-ui/Snackbar'
|
||||
import { LinearProgress } from 'material-ui/Progress'
|
||||
import {Helmet} from 'react-helmet'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import components
|
||||
|
||||
@@ -53,7 +55,6 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
|
||||
}
|
||||
|
||||
// Binding functions to `this`
|
||||
this.handleLoading = this.handleLoading.bind(this)
|
||||
this.handleMessage = this.handleMessage.bind(this)
|
||||
|
||||
}
|
||||
@@ -63,14 +64,6 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
|
||||
this.props.closeMessage()
|
||||
}
|
||||
|
||||
// Handle loading
|
||||
handleLoading = (status: boolean) => {
|
||||
this.setState({
|
||||
loading: status,
|
||||
authed: false
|
||||
})
|
||||
}
|
||||
|
||||
componentDidCatch (error: any, info: any) {
|
||||
console.log('===========Catched by React componentDidCatch==============')
|
||||
console.log(error, info)
|
||||
@@ -130,6 +123,11 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
|
||||
|
||||
return (
|
||||
<div id='master'>
|
||||
<Helmet>
|
||||
<meta charSet='utf-8' />
|
||||
<title>React Social Network</title>
|
||||
<link rel='canonical' href='https://github.com/Qolzam/react-social-network' />
|
||||
</Helmet>
|
||||
{sendFeedbackStatus ? <SendFeedback /> : ''}
|
||||
<div className='master__progress' style={{ display: (progress.visible ? 'block' : 'none') }}>
|
||||
<LinearProgress variant='determinate' value={progress.percent} />
|
||||
@@ -137,7 +135,7 @@ 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={global.showMasterLoading} handleLoading={this.handleLoading} />
|
||||
{progress.visible ? <MasterLoading /> : ''}
|
||||
<MasterRouter enabled={!loading} data={{uid}} />
|
||||
<Snackbar
|
||||
open={this.props.global.messageOpen}
|
||||
@@ -196,15 +194,16 @@ const mapDispatchToProps = (dispatch: any, ownProps: IMasterComponentProps) => {
|
||||
* Map state to props
|
||||
* @param {object} state
|
||||
*/
|
||||
const mapStateToProps = (state: any) => {
|
||||
const { authorize, global, user, post, comment, imageGallery, vote, notify, circle } = state
|
||||
const { sendFeedbackStatus } = global
|
||||
const mapStateToProps = (state: Map<string, any>) => {
|
||||
const authorize = Map(state.get('authorize', {})).toJS()
|
||||
const global = Map(state.get('global', {})).toJS()
|
||||
const { sendFeedbackStatus, progress } = global
|
||||
return {
|
||||
sendFeedbackStatus,
|
||||
progress,
|
||||
guest: authorize.guest,
|
||||
uid: authorize.uid,
|
||||
authed: authorize.authed,
|
||||
progress: global.progress,
|
||||
global: global
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { push } from 'react-router-redux'
|
||||
import AppBar from 'material-ui/AppBar'
|
||||
import Typography from 'material-ui/Typography'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
import FindPeople from 'src/components/findPeople'
|
||||
@@ -187,12 +188,12 @@ const mapDispatchToProps = (dispatch: any, ownProps: IPeopleComponentProps) => {
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IPeopleComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IPeopleComponentProps) => {
|
||||
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
uid: state.authorize.uid,
|
||||
circlesLoaded: state.circle.loaded
|
||||
translate: getTranslate(state.get('locale')),
|
||||
uid: state.getIn(['authorize', 'uid'], 0),
|
||||
circlesLoaded: state.getIn(['circle', 'loaded'])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
import Stream from 'containers/stream'
|
||||
@@ -76,12 +77,15 @@ const mapDispatchToProps = (dispatch: any,ownProps: IPostPageComponentProps) =>
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any,ownProps: IPostPageComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>,ownProps: IPostPageComponentProps) => {
|
||||
const {userId,postId} = ownProps.match.params
|
||||
const userInfo = state.getIn(['state', 'user', 'info', userId])
|
||||
let posts: Map<string, Map<string, any>> = Map({})
|
||||
posts = posts.set(postId, state.getIn(['post', 'userPosts', userId, postId], Map({})))
|
||||
return{
|
||||
avatar: state.user.info && state.user.info[userId] ? state.user.info[userId].avatar : '',
|
||||
name: state.user.info && state.user.info[userId] ? state.user.info[userId].fullName : '',
|
||||
posts: state.post.userPosts && state.post.userPosts[userId] ? {[postId] : { ...state.post.userPosts[userId][postId]}} : {}
|
||||
avatar: userInfo ? userInfo.avatar : '',
|
||||
name: userInfo ? userInfo.fullName : '',
|
||||
posts
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import Dialog from 'material-ui/Dialog'
|
||||
import Button from 'material-ui/Button'
|
||||
import RaisedButton from 'material-ui/Button'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
import ProfileHeader from 'src/components/profileHeader'
|
||||
@@ -19,6 +20,7 @@ import * as userActions from 'src/store/actions/userActions'
|
||||
import * as globalActions from 'src/store/actions/globalActions'
|
||||
import { IProfileComponentProps } from './IProfileComponentProps'
|
||||
import { IProfileComponentState } from './IProfileComponentState'
|
||||
import { Profile } from 'core/domain/users'
|
||||
|
||||
/**
|
||||
* Create component class
|
||||
@@ -78,13 +80,13 @@ export class ProfileComponent extends Component<IProfileComponentProps,IProfileC
|
||||
}
|
||||
const {loadPosts, hasMorePosts, translate} = this.props
|
||||
const St = StreamComponent as any
|
||||
const posts = Map(this.props.posts)
|
||||
return (
|
||||
<div style={styles.profile}>
|
||||
<div style={styles.header}>
|
||||
|
||||
<ProfileHeader tagLine={this.props.tagLine} avatar={this.props.avatar} isAuthedUser={this.props.isAuthedUser} banner={this.props.banner} fullName={this.props.name} followerCount={0} userId={this.props.userId}/>
|
||||
</div>
|
||||
{this.props.posts && Object.keys(this.props.posts).length !== 0
|
||||
{posts
|
||||
? (<div style={styles.content}>
|
||||
<div className='profile__title'>
|
||||
{translate!('profile.headPostsLabel', {userName: this.props.name})}
|
||||
@@ -92,7 +94,7 @@ export class ProfileComponent extends Component<IProfileComponentProps,IProfileC
|
||||
<div style={{ height: '24px' }}></div>
|
||||
|
||||
<St
|
||||
posts={this.props.posts}
|
||||
posts={posts}
|
||||
loadStream={loadPosts}
|
||||
hasMorePosts={hasMorePosts}
|
||||
displayWriting={false} />
|
||||
@@ -128,17 +130,18 @@ const mapDispatchToProps = (dispatch: any, ownProps: IProfileComponentProps) =>
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IProfileComponentProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IProfileComponentProps) => {
|
||||
const { userId } = ownProps.match.params
|
||||
const {uid} = state.authorize
|
||||
const hasMorePosts = state.post.profile.hasMoreData
|
||||
const posts = state.post.userPosts ? state.post.userPosts[userId] : {}
|
||||
const uid = state.getIn(['authorize', 'uid'], 0)
|
||||
const hasMorePosts = state.getIn(['post', 'profile', 'hasMoreData'])
|
||||
const posts = state.getIn(['post', 'userPosts', userId])
|
||||
const userProfile = state.getIn(['user', 'info', userId], {}) as Profile
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
avatar: state.user.info && state.user.info[userId] ? state.user.info[userId].avatar || '' : '',
|
||||
name: state.user.info && state.user.info[userId] ? state.user.info[userId].fullName || '' : '',
|
||||
banner: state.user.info && state.user.info[userId] ? state.user.info[userId].banner || '' : '',
|
||||
tagLine: state.user.info && state.user.info[userId] ? state.user.info[userId].tagLine || '' : '',
|
||||
translate: getTranslate(state.get('locale')),
|
||||
avatar: userProfile.avatar,
|
||||
name: userProfile.fullName,
|
||||
banner: userProfile.banner,
|
||||
tagLine: userProfile.tagLine,
|
||||
isAuthedUser: userId === uid,
|
||||
userId,
|
||||
posts,
|
||||
|
||||
@@ -179,7 +179,7 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IResetPasswordComponen
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IResetPasswordComponentProps) => {
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: ISettingComponentProps) =>
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: ISettingComponentProps) => {
|
||||
return {
|
||||
translate: getTranslate(state.locale)
|
||||
translate: getTranslate(state.get('locale'))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -287,7 +287,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: ISignupComponentProps) => {
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: ISignupComponentProps) => {
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
translate: getTranslate(state.get('locale')),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Post } from 'src/core/domain/posts'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
export interface IStreamComponentProps {
|
||||
|
||||
@@ -82,7 +83,7 @@ export interface IStreamComponentProps {
|
||||
* @type {{[postId: string]: Post}}
|
||||
* @memberof IStreamComponentProps
|
||||
*/
|
||||
posts: {[postId: string]: Post}
|
||||
posts: Map<string, Map<string, any>>
|
||||
|
||||
/**
|
||||
* Router match property
|
||||
|
||||
@@ -10,6 +10,7 @@ import Paper from 'material-ui/Paper'
|
||||
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List'
|
||||
import InfiniteScroll from 'react-infinite-scroller'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import { Map, List as ImuList } from 'immutable'
|
||||
|
||||
// - Import app components
|
||||
import PostComponent from 'src/components/post'
|
||||
@@ -128,56 +129,58 @@ export class StreamComponent extends Component<IStreamComponentProps, IStreamCom
|
||||
*/
|
||||
postLoad = () => {
|
||||
|
||||
let { posts, match } = this.props
|
||||
let { match } = this.props
|
||||
let posts: Map<string, Map<string, any>> = this.props.posts
|
||||
let { tag } = match.params
|
||||
if (posts === undefined || !(Object.keys(posts).length > 0)) {
|
||||
|
||||
if (posts === undefined || !(posts.keySeq().count() > 0)) {
|
||||
|
||||
return (
|
||||
|
||||
|
||||
<h1>
|
||||
'Nothing has shared.'
|
||||
</h1>
|
||||
|
||||
)
|
||||
} else {
|
||||
|
||||
let postBack = { divided: false, oddPostList: [], evenPostList: [] }
|
||||
let parsedPosts: any = []
|
||||
Object.keys(posts).forEach((postId) => {
|
||||
)
|
||||
} else {
|
||||
|
||||
let postBack = { divided: false, oddPostList: [], evenPostList: [] }
|
||||
let parsedPosts: ImuList<any> = ImuList()
|
||||
posts.forEach((post: Map<string, any>) => {
|
||||
if (tag) {
|
||||
let regex = new RegExp('#' + tag, 'g')
|
||||
let postMatch = posts[postId].body!.match(regex)
|
||||
let postMatch = String(post.get('body', '')).match(regex)
|
||||
if (postMatch !== null) {
|
||||
parsedPosts.push({ ...posts[postId] })
|
||||
parsedPosts = parsedPosts.push(post)
|
||||
}
|
||||
} else {
|
||||
parsedPosts.push({ ...posts[postId] })
|
||||
|
||||
parsedPosts = parsedPosts.push(post)
|
||||
}
|
||||
})
|
||||
const sortedPosts = PostAPI.sortObjectsDate(parsedPosts)
|
||||
if (sortedPosts.length > 6) {
|
||||
const sortedPosts = PostAPI.sortImuObjectsDate(parsedPosts)
|
||||
if (sortedPosts.count() > 6) {
|
||||
postBack.divided = true
|
||||
|
||||
|
||||
} else {
|
||||
postBack.divided = false
|
||||
}
|
||||
sortedPosts.forEach((post: Post, index: any) => {
|
||||
|
||||
let index = 0
|
||||
sortedPosts.forEach((post) => {
|
||||
|
||||
let newPost: any = (
|
||||
<div key={`${post.id!}-stream-div`}>
|
||||
|
||||
<div key={`${post!.get('id')!}-stream-div`}>
|
||||
|
||||
{index > 1 || (!postBack.divided && index > 0) ? <div style={{ height: '16px' }}></div> : ''}
|
||||
<PostComponent key={`${post.id!}-stream-div-post`} post={post} />
|
||||
<PostComponent key={`${post!.get('id')}-stream-div-post`} post={post! as any} />
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
if ((index % 2) === 1 && postBack.divided) {
|
||||
postBack.oddPostList.push(newPost as never)
|
||||
} else {
|
||||
postBack.evenPostList.push(newPost as never)
|
||||
}
|
||||
++index
|
||||
})
|
||||
return postBack
|
||||
}
|
||||
@@ -276,14 +279,15 @@ const mapDispatchToProps = (dispatch: any, ownProps: IStreamComponentProps) => {
|
||||
* @param {object} ownProps is the props belong to component
|
||||
* @return {object} props of component
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IStreamComponentProps) => {
|
||||
const { post } = state
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IStreamComponentProps) => {
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
const user = state.getIn(['user', 'info', uid])
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
avatar: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].avatar : '',
|
||||
fullName: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].fullName : ''
|
||||
translate: getTranslate(state.get('locale')),
|
||||
avatar: user.avatar || '',
|
||||
fullName: user.fullName || ''
|
||||
}
|
||||
}
|
||||
|
||||
// - Connect component to redux store
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(StreamComponent as any) as any)
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(StreamComponent as any) as any) as typeof StreamComponent
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import React, { Component } from 'react'
|
||||
|
||||
const asyncComponent = (importComponent: any) => {
|
||||
return class extends Component {
|
||||
state = {
|
||||
component: null
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
importComponent()
|
||||
.then((cmp: any) => {
|
||||
this.setState({component: cmp.default})
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const C: any = this.state.component
|
||||
|
||||
return C ? <C {...this.props} /> : null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default asyncComponent
|
||||
@@ -1,29 +1,31 @@
|
||||
// - Import react components
|
||||
import PrivateRoute from './PrivateRoute'
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { Route, Switch, withRouter, Redirect, NavLink } from 'react-router-dom'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import Loadable from 'react-loadable'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
import asyncComponent from 'hoc/asyncComponent/asyncComponent'
|
||||
import { IRouterProps } from './IRouterProps'
|
||||
import MasterLoadingComponent from 'components/masterLoading/MasterLoadingComponent'
|
||||
|
||||
// - Async Components
|
||||
const AsyncStream = asyncComponent(() => {
|
||||
return import('containers/stream')
|
||||
const AsyncStream = Loadable({
|
||||
loader: () => import('containers/stream'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
const AsyncProfile = asyncComponent(() => {
|
||||
return import('containers/profile')
|
||||
const AsyncProfile = Loadable({
|
||||
loader: () => import('containers/profile'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
const AsyncPostPage = asyncComponent(() => {
|
||||
return import('containers/postPage')
|
||||
const AsyncPostPage = Loadable({
|
||||
loader: () => import('containers/postPage'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
const AsyncPeople = asyncComponent(() => {
|
||||
return import('containers/people')
|
||||
const AsyncPeople = Loadable({
|
||||
loader: () => import('containers/people'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -32,7 +34,7 @@ const AsyncPeople = asyncComponent(() => {
|
||||
export class HomeRouter extends Component<IRouterProps, any> {
|
||||
render () {
|
||||
const { enabled, match, data, translate } = this.props
|
||||
const St = AsyncStream as any
|
||||
const St = AsyncStream
|
||||
return (
|
||||
enabled ? (
|
||||
<Switch>
|
||||
@@ -71,10 +73,10 @@ const mapDispatchToProps = (dispatch: any, ownProps: IRouterProps) => {
|
||||
/**
|
||||
* Map state to props
|
||||
*/
|
||||
const mapStateToProps = (state: any, ownProps: IRouterProps) => {
|
||||
const mapStateToProps = (state: Map<string, any>, ownProps: IRouterProps) => {
|
||||
return {
|
||||
translate: getTranslate(state.locale),
|
||||
currentLanguage: getActiveLanguage(state.locale).code,
|
||||
translate: getTranslate(state.get('locale')),
|
||||
currentLanguage: getActiveLanguage(state.get('locale')).code,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,33 +5,35 @@ import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { Route, Switch, withRouter, Redirect, NavLink } from 'react-router-dom'
|
||||
import Loadable from 'react-loadable'
|
||||
|
||||
import asyncComponent from 'hoc/asyncComponent/asyncComponent'
|
||||
import { IRouterProps } from './IRouterProps'
|
||||
import MasterLoadingComponent from 'components/masterLoading/MasterLoadingComponent'
|
||||
|
||||
// - Async Components
|
||||
const AsyncHome: any = asyncComponent(() => {
|
||||
return import('containers/home')
|
||||
const AsyncHome: any = Loadable({
|
||||
loader: () => import('containers/home'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
const AsyncSignup = asyncComponent(() => {
|
||||
return import('containers/signup')
|
||||
const AsyncSignup = Loadable({
|
||||
loader: () => import('containers/signup'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
const AsyncEmailVerification = asyncComponent(() => {
|
||||
return import('containers/emailVerification')
|
||||
const AsyncEmailVerification = Loadable({
|
||||
loader: () => import('containers/emailVerification'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
const AsyncResetPassword = asyncComponent(() => {
|
||||
return import('containers/resetPassword')
|
||||
const AsyncResetPassword = Loadable({
|
||||
loader: () => import('containers/resetPassword'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
const AsyncLogin = asyncComponent(() => {
|
||||
return import('containers/login')
|
||||
const AsyncLogin = Loadable({
|
||||
loader: () => import('containers/login'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
const AsyncSetting = asyncComponent(() => {
|
||||
return import('containers/setting')
|
||||
const AsyncSetting = Loadable({
|
||||
loader: () => import('containers/setting'),
|
||||
loading: MasterLoadingComponent,
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Route, Redirect } from 'react-router-dom'
|
||||
import { IRoute } from './IRoute'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
export class PrivateRoute extends Component<IRoute, any> {
|
||||
|
||||
@@ -19,10 +20,10 @@ export class PrivateRoute extends Component<IRoute, any> {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any, nexProps: IRoute) => {
|
||||
const { authorize } = state
|
||||
const mapStateToProps = (state: Map<string, any>, nexProps: IRoute) => {
|
||||
|
||||
return {
|
||||
authed: authorize.authed
|
||||
authed: state.getIn(['authorize', 'authed'])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Route, Redirect } from 'react-router-dom'
|
||||
import { IRoute } from './IRoute'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
export class PublicRoute extends Component<IRoute, any> {
|
||||
|
||||
@@ -19,10 +20,10 @@ export class PublicRoute extends Component<IRoute, any> {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any, nexProps: IRoute) => {
|
||||
const { authorize } = state
|
||||
const mapStateToProps = (state: Map<string, any>, nexProps: IRoute) => {
|
||||
|
||||
return {
|
||||
authed: authorize.authed
|
||||
authed: state.getIn(['authorize', 'authed', false])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import CommonAPI from 'api/CommonAPI'
|
||||
/**
|
||||
* Developer tools
|
||||
*/
|
||||
console.trace = CommonAPI.logger
|
||||
window['console']['trace'] = CommonAPI.logger
|
||||
|
||||
/**
|
||||
* Initialize container
|
||||
|
||||
@@ -3,6 +3,7 @@ import { User } from 'src/core/domain/users'
|
||||
import { Circle, UserTie } from 'src/core/domain/circles'
|
||||
import { SocialError } from 'src/core/domain/common'
|
||||
import * as moment from 'moment/moment'
|
||||
import { Map, List } from 'immutable'
|
||||
|
||||
// - Import action types
|
||||
import { CircleActionType } from 'constants/circleActionType'
|
||||
@@ -37,7 +38,8 @@ const userTieService: IUserTieService = provider.get<IUserTieService>(SocialProv
|
||||
export let dbAddCircle = (circleName: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
let circle: Circle = {
|
||||
creationDate: moment().unix(),
|
||||
name: circleName,
|
||||
@@ -47,7 +49,7 @@ export let dbAddCircle = (circleName: string) => {
|
||||
return circleService.addCircle(uid, circle).then((circleKey: string) => {
|
||||
circle.id = circleKey
|
||||
circle.ownerId = uid
|
||||
dispatch(addCircle(circle))
|
||||
dispatch(addCircle(Map(circle)))
|
||||
|
||||
}, (error: SocialError) => dispatch(globalActions.showMessage(error.message)))
|
||||
|
||||
@@ -59,9 +61,9 @@ export let dbAddCircle = (circleName: string) => {
|
||||
*/
|
||||
export const dbFollowUser = (followingCircleId: string, userFollowing: UserTie) => {
|
||||
return (dispatch: Function, getState: Function) => {
|
||||
const state = getState()
|
||||
let uid: string = state.authorize.uid
|
||||
let user: User = { ...state.user.info[uid], userId: uid }
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
let user: User = { ...state.getIn(['user', 'info', uid]), userId: uid }
|
||||
|
||||
// Set server request status to {Sent} for following user
|
||||
const followReqestModel = createFollowRequest(userFollowing.userId!)
|
||||
@@ -74,15 +76,16 @@ export const dbFollowUser = (followingCircleId: string, userFollowing: UserTie)
|
||||
[followingCircleId]
|
||||
)
|
||||
.then(() => {
|
||||
dispatch(addFollowingUser(
|
||||
new UserTie(
|
||||
userFollowing.userId!,
|
||||
moment().unix(),
|
||||
userFollowing.fullName,
|
||||
userFollowing.avatar,
|
||||
false,
|
||||
[followingCircleId]
|
||||
)))
|
||||
let userTie: Map<string, any> = Map(new UserTie(
|
||||
userFollowing.userId!,
|
||||
moment().unix(),
|
||||
userFollowing.fullName,
|
||||
userFollowing.avatar,
|
||||
false,
|
||||
))
|
||||
userTie = userTie.set('circleIdList', List([followingCircleId]))
|
||||
|
||||
dispatch(addFollowingUser(userTie))
|
||||
|
||||
// Set server request status to {OK} for following user
|
||||
followReqestModel.status = ServerRequestStatusType.OK
|
||||
@@ -111,11 +114,11 @@ export const dbFollowUser = (followingCircleId: string, userFollowing: UserTie)
|
||||
/**
|
||||
* Update user in circle/circles
|
||||
*/
|
||||
export let dbUpdateUserInCircles = (circleIdList: string[], userFollowing: UserTie) => {
|
||||
export let dbUpdateUserInCircles = (circleIdList: List<string>, userFollowing: UserTie) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
const state = getState()
|
||||
let uid: string = state.authorize.uid
|
||||
let user: User = { ...state.user.info[uid], userId: uid }
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
let user: User = { ...state.getIn(['user', 'info', uid]), userId: uid }
|
||||
|
||||
// Set server request status to {Sent}
|
||||
const addToCircleRequest = createAddToCircleRequest(userFollowing.userId!)
|
||||
@@ -127,18 +130,18 @@ export let dbUpdateUserInCircles = (circleIdList: string[], userFollowing: UserT
|
||||
return userTieService.updateUsersTie(
|
||||
{ userId: user.userId!, fullName: user.fullName, avatar: user.avatar, approved: false },
|
||||
{ userId: userFollowing.userId!, fullName: userFollowing.fullName, avatar: userFollowing.avatar, approved: false },
|
||||
circleIdList
|
||||
circleIdList.toJS()
|
||||
)
|
||||
.then(() => {
|
||||
dispatch(addFollowingUser(
|
||||
new UserTie(
|
||||
userFollowing.userId!,
|
||||
moment().unix(),
|
||||
userFollowing.fullName,
|
||||
userFollowing.avatar,
|
||||
false,
|
||||
circleIdList
|
||||
)))
|
||||
let userTie: Map<string, any> = Map(new UserTie(
|
||||
userFollowing.userId!,
|
||||
moment().unix(),
|
||||
userFollowing.fullName,
|
||||
userFollowing.avatar,
|
||||
false
|
||||
))
|
||||
userTie = userTie.set('circleIdList', circleIdList)
|
||||
dispatch(addFollowingUser(userTie))
|
||||
|
||||
// Set server request status to {OK}
|
||||
addToCircleRequest.status = ServerRequestStatusType.OK
|
||||
@@ -167,7 +170,8 @@ export let dbUpdateUserInCircles = (circleIdList: string[], userFollowing: UserT
|
||||
export let dbDeleteFollowingUser = (userFollowingId: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
// Set server request status to {Sent}
|
||||
const deleteFollowingUserRequest = createdeleteFollowingUserRequest(userFollowingId)
|
||||
@@ -208,16 +212,17 @@ export let dbDeleteFollowingUser = (userFollowingId: string) => {
|
||||
*/
|
||||
export const dbUpdateCircle = (newCircle: Circle) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
// Write the new data simultaneously in the list
|
||||
let circle: Circle = {...getState().circle.circleList[newCircle.id!]}
|
||||
circle.name = newCircle.name
|
||||
return circleService.updateCircle(uid, newCircle.id!, circle)
|
||||
let circle: Map<string, any> = state.getIn(['circle', 'circleList', newCircle.id!])
|
||||
circle = circle.set('name', newCircle.name)
|
||||
return circleService.updateCircle(uid, newCircle.id!, circle.toJS())
|
||||
.then(() => {
|
||||
dispatch(updateCircle({ id: newCircle.id, ...circle }))
|
||||
circle = circle.set('id', newCircle.id)
|
||||
dispatch(updateCircle(circle))
|
||||
}, (error: SocialError) => {
|
||||
dispatch(globalActions.showMessage(error.message))
|
||||
})
|
||||
@@ -232,7 +237,8 @@ export const dbDeleteCircle = (circleId: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
return circleService.deleteCircle(uid, circleId)
|
||||
.then(() => {
|
||||
@@ -249,7 +255,8 @@ export const dbDeleteCircle = (circleId: string) => {
|
||||
*/
|
||||
export const dbGetCircles = () => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
if (uid) {
|
||||
|
||||
return circleService.getCircles(uid)
|
||||
@@ -269,7 +276,8 @@ export const dbGetCircles = () => {
|
||||
*/
|
||||
export const dbGetUserTies = () => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
if (uid) {
|
||||
userTieService.getUserTies(uid).then((result) => {
|
||||
|
||||
@@ -289,7 +297,8 @@ export const dbGetUserTies = () => {
|
||||
*/
|
||||
export const dbGetFollowers = () => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
if (uid) {
|
||||
userTieService.getUserTieSender(uid).then((result) => {
|
||||
|
||||
@@ -367,7 +376,7 @@ const createdeleteFollowingUserRequest = (userFollowingId: string) => {
|
||||
/**
|
||||
* Add a circle
|
||||
*/
|
||||
export const addCircle = (circle: Circle) => {
|
||||
export const addCircle = (circle: Map<string, any>) => {
|
||||
return {
|
||||
type: CircleActionType.ADD_CIRCLE,
|
||||
payload: { circle }
|
||||
@@ -377,7 +386,7 @@ export const addCircle = (circle: Circle) => {
|
||||
/**
|
||||
* Update a circle
|
||||
*/
|
||||
export const updateCircle = (circle: Circle) => {
|
||||
export const updateCircle = (circle: Map<string, any>) => {
|
||||
return {
|
||||
type: CircleActionType.UPDATE_CIRCLE,
|
||||
payload: { circle }
|
||||
@@ -438,7 +447,7 @@ export const closeCircleSettings = (circleId: string) => {
|
||||
/**
|
||||
* Add following user
|
||||
*/
|
||||
export const addFollowingUser = (userTie: UserTie) => {
|
||||
export const addFollowingUser = (userTie: Map<string, any>) => {
|
||||
return {
|
||||
type: CircleActionType.ADD_FOLLOWING_USER,
|
||||
payload: { userTie }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// - Import react components
|
||||
import moment from 'moment/moment'
|
||||
import _ from 'lodash'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import domain
|
||||
import { Comment } from 'src/core/domain/comments'
|
||||
@@ -40,14 +41,14 @@ export const dbAddComment = (ownerPostUserId: string, newComment: Comment, callB
|
||||
|
||||
dispatch(globalActions.showTopLoading())
|
||||
|
||||
const state = getState()
|
||||
let uid: string = state.authorize.uid
|
||||
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
const currentUser = state.getIn(['user', 'info', uid])
|
||||
let comment: Comment = {
|
||||
score: 0,
|
||||
creationDate: moment().unix(),
|
||||
userDisplayName: state.user.info[uid].fullName,
|
||||
userAvatar: state.user.info[uid].avatar,
|
||||
userDisplayName: currentUser.fullName,
|
||||
userAvatar: currentUser.avatar,
|
||||
userId: uid,
|
||||
postId: newComment.postId,
|
||||
text: newComment.text
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// - Import image gallery action types
|
||||
import { GlobalActionType } from 'constants/globalActionType'
|
||||
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import actions
|
||||
import * as serverActions from 'store/actions/serverActions'
|
||||
@@ -24,8 +25,8 @@ const commonService: ICommonService = provider.get<ICommonService>(SocialProvide
|
||||
*/
|
||||
export let dbSendFeed = (newFeed: Feed) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
// Set server request status to {Sent}
|
||||
const feedbackRequest = createFeedbackRequest(uid)
|
||||
@@ -49,8 +50,8 @@ export let dbSendFeed = (newFeed: Feed) => {
|
||||
// - Show notification of request
|
||||
export const showNotificationRequest = () => {
|
||||
return (dispatch: Function, getState: Function) => {
|
||||
const state = getState()
|
||||
const translate = getTranslate(state.locale)
|
||||
const state: Map<string, any> = getState()
|
||||
const translate = getTranslate(state.get('locale'))
|
||||
return dispatch(showMessage(String(translate('common.sentRequestMessage'))))
|
||||
}
|
||||
}
|
||||
@@ -58,8 +59,8 @@ export const showNotificationRequest = () => {
|
||||
// - Show notification of success
|
||||
export const showNotificationSuccess = () => {
|
||||
return (dispatch: Function, getState: Function) => {
|
||||
const state = getState()
|
||||
const translate = getTranslate(state.locale)
|
||||
const state: Map<string, any> = getState()
|
||||
const translate = getTranslate(state.get('locale'))
|
||||
return dispatch(showMessage(String(translate('common.successfulRequestMessage'))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// - Import react componetns
|
||||
import moment from 'moment/moment'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import domain
|
||||
import { Image } from 'src/core/domain/imageGallery'
|
||||
@@ -28,7 +29,8 @@ const imageGalleryService: IImageGalleryService = provider.get<IImageGalleryServ
|
||||
*/
|
||||
export const dbGetImageGallery = () => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
if (uid) {
|
||||
|
||||
return imageGalleryService.getImageGallery(uid)
|
||||
@@ -51,7 +53,8 @@ export const dbGetImageGallery = () => {
|
||||
export const dbSaveImage = (imageURL: string,imageFullPath: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
let image: Image = {
|
||||
creationDate: moment().unix(),
|
||||
deleteDate: '',
|
||||
@@ -82,7 +85,8 @@ export const dbDeleteImage = (id: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
return imageGalleryService.deleteImage(uid,id)
|
||||
.then(() => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// - Import domain
|
||||
import { Notification } from 'src/core/domain/notifications'
|
||||
import { SocialError } from 'src/core/domain/common'
|
||||
import { Map, fromJS } from 'immutable'
|
||||
|
||||
// - Import action types
|
||||
import { NotificationActionType } from 'constants/notificationActionType'
|
||||
@@ -23,7 +24,6 @@ const notificationService: INotificationService = provider.get<INotificationServ
|
||||
|
||||
/**
|
||||
* Add notificaition to database
|
||||
* @param {object} newNotify user notificaition
|
||||
*/
|
||||
export const dbAddNotification = (newNotify: Notification) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
@@ -50,16 +50,17 @@ export const dbAddNotification = (newNotify: Notification) => {
|
||||
*/
|
||||
export const dbGetNotifications = () => {
|
||||
return (dispatch: Function , getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
if (uid) {
|
||||
return notificationService.getNotifications(uid,
|
||||
(notifications: { [notifyId: string]: Notification} ) => {
|
||||
Object.keys(notifications).forEach((key => {
|
||||
if (!getState().user.info[notifications[key].notifierUserId]) {
|
||||
if (!state.getIn(['user', 'info', 'notifications', 'key','notifierUserId'])) {
|
||||
dispatch(userActions.dbGetUserInfoByUserId(notifications[key].notifierUserId,''))
|
||||
}
|
||||
}))
|
||||
dispatch(addNotifyList(notifications))
|
||||
dispatch(addNotifyList(fromJS(notifications)))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -73,7 +74,8 @@ export const dbDeleteNotification = (id: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
return notificationService.deleteNotification(id,uid).then(() => {
|
||||
dispatch(deleteNotify(id))
|
||||
@@ -90,14 +92,14 @@ export const dbDeleteNotification = (id: string) => {
|
||||
export const dbSeenNotification = (id: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
let notify: Notification = getState().notify.userNotifies[id]
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
let notify: Map<string, any> = state.getIn(['notify', 'userNotifies', id])
|
||||
|
||||
let updatedNotification: Notification = {
|
||||
description: notify.description,
|
||||
url: notify.url,
|
||||
notifierUserId: notify.notifierUserId,
|
||||
description: notify.get('description'),
|
||||
url: notify.get('url'),
|
||||
notifierUserId: notify.get('notifierUserId'),
|
||||
notifyRecieverUserId: uid,
|
||||
isSeen: true
|
||||
}
|
||||
@@ -127,7 +129,7 @@ export const addNotify = () => {
|
||||
* Add notificaition list
|
||||
* @param {[notifyId: string]: Notification} userNotifies an array of notificaitions
|
||||
*/
|
||||
export const addNotifyList = (userNotifies: {[notifyId: string]: Notification}) => {
|
||||
export const addNotifyList = (userNotifies: Map<string, any>) => {
|
||||
|
||||
return {
|
||||
type: NotificationActionType.ADD_NOTIFY_LIST,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// - Import domain
|
||||
import { Post } from 'src/core/domain/posts'
|
||||
import { SocialError } from 'src/core/domain/common'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import utility components
|
||||
import moment from 'moment/moment'
|
||||
@@ -27,8 +28,8 @@ const postService: IPostService = provider.get<IPostService>(SocialProviderTypes
|
||||
*/
|
||||
export let dbAddPost = (newPost: Post, callBack: Function) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
let post: Post = {
|
||||
postTypeId: 0,
|
||||
creationDate: moment().unix(),
|
||||
@@ -70,8 +71,8 @@ export const dbAddImagePost = (newPost: Post, callBack: Function) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
dispatch(globalActions.showTopLoading())
|
||||
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
let post: Post = {
|
||||
postTypeId: 1,
|
||||
creationDate: moment().unix(),
|
||||
@@ -111,12 +112,12 @@ export const dbAddImagePost = (newPost: Post, callBack: Function) => {
|
||||
/**
|
||||
* Update a post from database
|
||||
*/
|
||||
export const dbUpdatePost = (updatedPost: Post, callBack: Function) => {
|
||||
export const dbUpdatePost = (updatedPost: Map<string, any>, callBack: Function) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
console.trace('update post ', updatedPost)
|
||||
|
||||
dispatch(globalActions.showTopLoading())
|
||||
|
||||
return postService.updatePost(updatedPost).then(() => {
|
||||
return postService.updatePost(updatedPost.toJS()).then(() => {
|
||||
|
||||
dispatch(updatePost(updatedPost))
|
||||
callBack()
|
||||
@@ -141,8 +142,9 @@ export const dbDeletePost = (id: string) => {
|
||||
|
||||
dispatch(globalActions.showTopLoading())
|
||||
|
||||
const state: Map<string, any> = getState()
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
return postService.deletePost(id).then(() => {
|
||||
dispatch(deletePost(uid, id))
|
||||
@@ -162,12 +164,12 @@ export const dbDeletePost = (id: string) => {
|
||||
*/
|
||||
export const dbGetPosts = (page: number = 0, limit: number = 10) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
const state = getState()
|
||||
const {stream} = state.post
|
||||
const lastPageRequest = stream.lastPageRequest
|
||||
const lastPostId = stream.lastPostId
|
||||
const state: Map<string, any> = getState()
|
||||
const stream: Map<string, any> = state.getIn(['post', 'stream'])
|
||||
const lastPageRequest = stream.get('lastPageRequest')
|
||||
const lastPostId = stream.get('lastPostId')
|
||||
|
||||
let uid: string = state.authorize.uid
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
if (uid && lastPageRequest !== page) {
|
||||
return postService.getPosts(uid, lastPostId, page, limit).then((result) => {
|
||||
if (!result.posts || !(result.posts.length > 0)) {
|
||||
@@ -207,12 +209,12 @@ export const dbGetPosts = (page: number = 0, limit: number = 10) => {
|
||||
*/
|
||||
export const dbGetPostsByUserId = (userId: string, page: number = 0, limit: number = 10) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
const state = getState()
|
||||
const {profile} = state.post
|
||||
const lastPageRequest = profile[userId] ? profile[userId].lastPageRequest : -1
|
||||
const lastPostId = profile[userId] ? profile[userId].lastPostId : ''
|
||||
const state: Map<string, any> = getState()
|
||||
const {profile} = state.get('post')
|
||||
const lastPageRequest = state.getIn(['post','profile', userId, 'lastPageRequest'], -1 )
|
||||
const lastPostId = state.getIn(['post','profile', userId, 'lastPostId'], '' )
|
||||
|
||||
let uid: string = state.authorize.uid
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
if (uid && lastPageRequest !== page) {
|
||||
|
||||
@@ -282,13 +284,33 @@ export const addPost = (uid: string, post: Post) => {
|
||||
/**
|
||||
* Update a post
|
||||
*/
|
||||
export const updatePost = (post: Post) => {
|
||||
export const updatePost = (post: Map<string, any>) => {
|
||||
return {
|
||||
type: PostActionType.UPDATE_POST,
|
||||
payload: { post }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the comments of post
|
||||
*/
|
||||
export const updatePostComments = (comments: Map<string, any>) => {
|
||||
return {
|
||||
type: PostActionType.UPDATE_POST,
|
||||
payload: comments
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the votes of post
|
||||
*/
|
||||
export const updatePostVotes = (votes: Map<string, any>) => {
|
||||
return {
|
||||
type: PostActionType.UPDATE_POST,
|
||||
payload: votes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a post
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export enum ServerRequestStatusType {
|
||||
Sent = 'Sent',
|
||||
NoAction = 'NoAction',
|
||||
OK = 'OK',
|
||||
Error = 'Error'
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// - Import react components
|
||||
import { provider } from 'src/socialEngine'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import domain
|
||||
import { Profile } from 'src/core/domain/users'
|
||||
import { SocialError } from 'src/core/domain/common'
|
||||
@@ -25,7 +27,8 @@ const userService: IUserService = provider.get<IUserService>(SocialProviderTypes
|
||||
*/
|
||||
export const dbGetUserInfo = () => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
if (uid) {
|
||||
return userService.getUserProfile(uid).then((userProfile: Profile) => {
|
||||
dispatch(addUserInfo(uid, {
|
||||
@@ -54,7 +57,8 @@ export const dbGetUserInfoByUserId = (uid: string, callerKey: string) => {
|
||||
return (dispatch: Function, getState: Function) => {
|
||||
if (uid) {
|
||||
|
||||
let caller = getState().global.temp.caller
|
||||
const state: Map<string, any> = getState()
|
||||
let caller = state.getIn(['global', 'temp', 'caller'])
|
||||
if ( caller && caller.indexOf(`dbGetUserInfoByUserId-${uid}`) > -1) {
|
||||
return undefined
|
||||
}
|
||||
@@ -95,11 +99,10 @@ export const dbGetUserInfoByUserId = (uid: string, callerKey: string) => {
|
||||
*/
|
||||
export const dbUpdateUserInfo = (newProfile: Profile) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
console.trace('newProfile', newProfile)
|
||||
// Get current user id
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
let profile: Profile = getState().user.info[uid]
|
||||
let profile: Profile = state.getIn(['user', 'info', uid])
|
||||
let updatedProfile: Profile = {
|
||||
avatar: newProfile.avatar || profile.avatar || '',
|
||||
banner: newProfile.banner || profile.banner || 'https://firebasestorage.googleapis.com/v0/b/open-social-33d92.appspot.com/o/images%2F751145a1-9488-46fd-a97e-04018665a6d3.JPG?alt=media&token=1a1d5e21-5101-450e-9054-ea4a20e06c57',
|
||||
@@ -126,33 +129,27 @@ export const dbUpdateUserInfo = (newProfile: Profile) => {
|
||||
// - Get people info from database
|
||||
export const dbGetPeopleInfo = (page: number, limit: number) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
const state = getState()
|
||||
const {people} = state.user
|
||||
const lastPageRequest = people.lastPageRequest
|
||||
const lastUserId = people.lastUserId
|
||||
const state: Map<string, any> = getState()
|
||||
const people: Map<string, any> = state.getIn(['user', 'people'])
|
||||
const lastPageRequest = people.get('lastPageRequest')
|
||||
const lastUserId = people.get('lastUserId')
|
||||
|
||||
let uid: string = state.authorize.uid
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
|
||||
if (uid && lastPageRequest !== page) {
|
||||
|
||||
return userService.getUsersProfile(uid, lastUserId, page, limit).then((result) => {
|
||||
|
||||
if (!result.users || !(result.users.length > 0)) {
|
||||
return dispatch(notMoreDataPeople())
|
||||
}
|
||||
// Store last user Id
|
||||
dispatch(lastUserPeople(result.newLastUserId))
|
||||
|
||||
let parsedData: {[userId: string]: Profile} = {}
|
||||
result.users.forEach((post) => {
|
||||
const userId = Object.keys(post)[0]
|
||||
const postData = post[userId]
|
||||
parsedData = {
|
||||
...parsedData,
|
||||
[userId]: {
|
||||
...postData
|
||||
}
|
||||
}
|
||||
let parsedData: Map<string, Profile> = Map({})
|
||||
result.users.forEach((user) => {
|
||||
const userId = Object.keys(user)[0]
|
||||
const userData = user[userId]
|
||||
parsedData = parsedData.set(userId, userData)
|
||||
})
|
||||
dispatch(addPeopleInfo(parsedData))
|
||||
})
|
||||
@@ -176,9 +173,8 @@ export const addUserInfo = (uid: string, info: Profile) => {
|
||||
|
||||
/**
|
||||
* Add people information
|
||||
* @param {[userId: string]: Profile} infoList is the lst of information about users
|
||||
*/
|
||||
export const addPeopleInfo = (infoList: {[userId: string]: Profile}) => {
|
||||
export const addPeopleInfo = (infoList: Map<string, Profile>) => {
|
||||
return {
|
||||
type: UserActionType.ADD_PEOPLE_INFO,
|
||||
payload: infoList
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import moment from 'moment/moment'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
// - Import action types
|
||||
import { VoteActionType } from 'constants/voteActionType'
|
||||
@@ -31,20 +32,22 @@ const voteService: IVoteService = provider.get<IVoteService>(SocialProviderTypes
|
||||
export const dbAddVote = (postId: string,ownerPostUserId: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
|
||||
const state = getState()
|
||||
let uid: string = state.authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
const currentUser = state.getIn(['user', 'info', uid])
|
||||
let vote: Vote = {
|
||||
postId: postId,
|
||||
creationDate: moment().unix(),
|
||||
userDisplayName: getState().user.info[uid].fullName,
|
||||
userAvatar: getState().user.info[uid].avatar,
|
||||
userDisplayName: currentUser.fullName,
|
||||
userAvatar: currentUser.avatar,
|
||||
userId: uid
|
||||
}
|
||||
const post: Post = state.post.userPosts[ownerPostUserId][postId]
|
||||
|
||||
post.score! += 1
|
||||
post.votes = { ...post.votes!, [uid]: true}
|
||||
dispatch(postActions.updatePost(post))
|
||||
const post: Map<string, any> = state.getIn(['post', 'userPosts', ownerPostUserId, postId])
|
||||
const score = Number(post.get('score', 0)) + 1
|
||||
const votedPost = post
|
||||
.set('score', score)
|
||||
.setIn(['votes',uid], true)
|
||||
dispatch(postActions.updatePost(votedPost))
|
||||
|
||||
return voteService.addVote(vote).then((voteKey: string) => {
|
||||
if (uid !== ownerPostUserId) {
|
||||
@@ -59,9 +62,11 @@ export const dbAddVote = (postId: string,ownerPostUserId: string) => {
|
||||
|
||||
})
|
||||
.catch((error) => {
|
||||
post.score! -= 1
|
||||
post.votes = { ...post.votes!, [uid]: false}
|
||||
dispatch(postActions.updatePost(post))
|
||||
const score = post.get('score', 0) - 1
|
||||
const votedPost = post
|
||||
.set('score', score)
|
||||
.setIn(['votes',uid], false)
|
||||
dispatch(postActions.updatePost(votedPost))
|
||||
dispatch(globalActions.showMessage(error.message))
|
||||
})
|
||||
}
|
||||
@@ -72,15 +77,15 @@ export const dbAddVote = (postId: string,ownerPostUserId: string) => {
|
||||
*/
|
||||
export const dbGetVotes = (userId: string, postId: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
let uid: string = getState().authorize.uid
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
if (uid) {
|
||||
|
||||
return voteService
|
||||
.getVotes(postId)
|
||||
.then((postVotes: { [postId: string]: { [voteId: string]: Vote } }) => {
|
||||
dispatch(addVoteList(postVotes))
|
||||
const state = getState()
|
||||
const post: Post = state.post.userPosts[userId][postId]
|
||||
const post: Post = state.getIn(['post', 'userPosts', userId, postId])
|
||||
if (!post) {
|
||||
return
|
||||
}
|
||||
@@ -101,18 +106,21 @@ export const dbGetVotes = (userId: string, postId: string) => {
|
||||
*/
|
||||
export const dbDeleteVote = (postId: string, ownerPostUserId: string) => {
|
||||
return (dispatch: any, getState: Function) => {
|
||||
const state = getState()
|
||||
// Get current user id
|
||||
let uid: string = state.authorize.uid
|
||||
const post: Post = state.post.userPosts[ownerPostUserId][postId]
|
||||
post.score! -= 1
|
||||
post.votes = { ...post.votes!, [uid]: false}
|
||||
dispatch(postActions.updatePost(post))
|
||||
const state: Map<string, any> = getState()
|
||||
let uid: string = state.getIn(['authorize', 'uid'])
|
||||
const post: Map<string, any> = state.getIn(['post', 'userPosts', ownerPostUserId, postId])
|
||||
const score = post.get('score', 0) - 1
|
||||
const votedPost = post
|
||||
.set('score', score)
|
||||
.setIn(['votes',uid], false)
|
||||
dispatch(postActions.updatePost(votedPost))
|
||||
return voteService.deleteVote(uid, postId).then(x => x)
|
||||
.catch((error: any) => {
|
||||
post.score! += 1
|
||||
post.votes = { ...post.votes!, [uid]: true}
|
||||
dispatch(postActions.updatePost(post))
|
||||
const score = post.get('score', 0) + 1
|
||||
const votedPost = post
|
||||
.set('score', score)
|
||||
.setIn(['votes',uid], true)
|
||||
dispatch(postActions.updatePost(votedPost))
|
||||
dispatch(globalActions.showMessage(error.message))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
// - Import external components
|
||||
import * as redux from 'redux'
|
||||
import { createStore, applyMiddleware, compose, Store } from 'redux'
|
||||
import { composeWithDevTools } from 'redux-devtools-extension'
|
||||
import thunk from 'redux-thunk'
|
||||
import { routerMiddleware } from 'react-router-redux'
|
||||
import createHistory from 'history/createBrowserHistory'
|
||||
import createSagaMiddleware, { END } from 'redux-saga'
|
||||
import { createLogger } from 'redux-logger'
|
||||
import { rootReducer } from 'store/reducers'
|
||||
import { fromJS, Iterable, Map } from 'immutable'
|
||||
import DevTools from './devTools'
|
||||
// Create a history of your choosing (we're using a browser history in this case)
|
||||
export const history = createHistory()
|
||||
|
||||
// - Build the middleware for intercepting and dispatching navigation actions
|
||||
const logger = createLogger()
|
||||
// Logger option for transforming immutable js
|
||||
const logger = createLogger({
|
||||
stateTransformer: (state: Map<string, any>) => {
|
||||
|
||||
return state.toJS()
|
||||
}
|
||||
})
|
||||
|
||||
const sagaMiddleware = createSagaMiddleware()
|
||||
// - initial state
|
||||
let initialState = {
|
||||
@@ -19,9 +27,11 @@ let initialState = {
|
||||
}
|
||||
|
||||
// - Config and create store of redux
|
||||
let store: redux.Store<any> = redux.createStore(rootReducer, initialState, redux.compose(
|
||||
redux.applyMiddleware(logger,thunk, routerMiddleware(history), sagaMiddleware),
|
||||
DevTools.instrument()
|
||||
const composeEnhancers = composeWithDevTools({
|
||||
// Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
|
||||
})
|
||||
let store: Store<any> = createStore(rootReducer, fromJS(initialState), composeEnhancers(
|
||||
applyMiddleware(logger,thunk, routerMiddleware(history), sagaMiddleware)
|
||||
))
|
||||
|
||||
export default {store, runSaga: sagaMiddleware.run, close: () => store.dispatch(END), history}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { routerMiddleware } from 'react-router-redux'
|
||||
import createHistory from 'history/createBrowserHistory'
|
||||
import createSagaMiddleware, { END } from 'redux-saga'
|
||||
import { rootReducer } from 'store/reducers'
|
||||
import { fromJS } from 'immutable'
|
||||
// Create a history of your choosing (we're using a browser history in this case)
|
||||
export const history = createHistory()
|
||||
|
||||
@@ -16,7 +17,7 @@ let initialState = {
|
||||
}
|
||||
|
||||
// - Config and create store of redux
|
||||
let store: redux.Store<any> = redux.createStore(rootReducer, initialState, redux.compose(
|
||||
let store: redux.Store<any> = redux.createStore(rootReducer, fromJS(initialState), redux.compose(
|
||||
redux.applyMiddleware(thunk, routerMiddleware(history), sagaMiddleware)
|
||||
))
|
||||
|
||||
|
||||
@@ -6,41 +6,35 @@ import { AuthorizeActionType } from 'constants/authorizeActionType'
|
||||
|
||||
import { IAuthorizeAction } from './IAuthorizeAction'
|
||||
import { AuthorizeState } from './AuthorizeState'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
/**
|
||||
* Authorize reducer
|
||||
* @param {object} state
|
||||
* @param {object} action
|
||||
*/
|
||||
export let authorizeReducer = (state: AuthorizeState = new AuthorizeState(), action: IAuthorizeAction) => {
|
||||
export let authorizeReducer = (state = Map(new AuthorizeState()), action: IAuthorizeAction) => {
|
||||
const { payload } = action
|
||||
switch (action.type) {
|
||||
case AuthorizeActionType.LOGIN:
|
||||
return{
|
||||
...state,
|
||||
uid: payload.uid,
|
||||
authed: true,
|
||||
guest: false,
|
||||
isVerifide: payload.isVerifide
|
||||
}
|
||||
case AuthorizeActionType.LOGOUT:
|
||||
return{
|
||||
...state,
|
||||
uid: 0,
|
||||
authed: false,
|
||||
guest: true
|
||||
}
|
||||
return state
|
||||
.set('uid', payload.uid)
|
||||
.set('authed', true)
|
||||
.set('guest', false)
|
||||
.set('isVerifide', payload.isVerifide)
|
||||
|
||||
case AuthorizeActionType.LOGOUT:
|
||||
return state
|
||||
.set('uid', 0)
|
||||
.set('authed', false)
|
||||
.set('guest', true)
|
||||
.set('isVerifide', false)
|
||||
case AuthorizeActionType.SIGNUP:
|
||||
return{
|
||||
...state,
|
||||
uid: payload.userId
|
||||
}
|
||||
return state
|
||||
.set('uid', payload.userId)
|
||||
case AuthorizeActionType.UPDATE_PASSWORD:
|
||||
return{
|
||||
...state,
|
||||
updatePassword: payload.updatePassword
|
||||
}
|
||||
return state
|
||||
.set('updatePassword', payload.updatePassword)
|
||||
default:
|
||||
return state
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
const getCurrentUser = (state: any) => (state.user.info && state.authorize.uid) ? state.user.info[state.authorize.uid] : null
|
||||
import {Map} from 'immutable'
|
||||
const getCurrentUser = (state: Map<any, string>) => {
|
||||
const uid = state.getIn(['authorize', 'uid'])
|
||||
return state.getIn(['user', 'info', uid])
|
||||
}
|
||||
|
||||
export const authorizeSelector = {
|
||||
getCurrentUser
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Circle, UserTie } from 'src/core/domain/circles'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
/**
|
||||
* Circle state
|
||||
@@ -12,19 +13,19 @@ export class CircleState {
|
||||
*
|
||||
* @memberof CircleState
|
||||
*/
|
||||
userTies: { [userId: string]: UserTie } = {}
|
||||
userTies: Map<string, UserTie> = Map({})
|
||||
|
||||
/**
|
||||
* The list of users belong to users circle
|
||||
*
|
||||
* @memberof CircleState
|
||||
*/
|
||||
userTieds: { [userId: string]: UserTie } = {}
|
||||
userTieds: Map<string, UserTie> = Map({})
|
||||
|
||||
/**
|
||||
* The list of circle of current user
|
||||
*/
|
||||
circleList: { [circleId: string]: Circle }
|
||||
circleList: Map<string, Circle> = Map({})
|
||||
|
||||
/**
|
||||
* Whether select circle box is open for the selected user
|
||||
@@ -39,7 +40,7 @@ export class CircleState {
|
||||
/**
|
||||
* Keep selected circles for refere user
|
||||
*/
|
||||
selectedCircles: { [userId: string]: string[] }
|
||||
selectedCircles: Map<string, string[]> = Map({})
|
||||
|
||||
/**
|
||||
* Whether the select circles box for referer user is open
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// - Import react components
|
||||
import moment from 'moment/moment'
|
||||
import _ from 'lodash'
|
||||
import { Map, List } from 'immutable'
|
||||
|
||||
// - Import domain
|
||||
import { User } from 'src/core/domain/users'
|
||||
@@ -12,245 +13,120 @@ import { CircleActionType } from 'constants/circleActionType'
|
||||
import { CircleState } from './CircleState'
|
||||
import { ICircleAction } from './ICircleAction'
|
||||
|
||||
/**
|
||||
* Add circle
|
||||
*/
|
||||
const addCircle = (state: any , payload: any) => {
|
||||
const circle: Map<string, any> = payload.circle
|
||||
return state
|
||||
.setIn(['circleList', circle.get('id')], payload.circle)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update circle
|
||||
*/
|
||||
const updateCircle = (state: any , payload: any) => {
|
||||
const circle: Map<string, any> = payload.circle
|
||||
return state
|
||||
.setIn(['openSetting', circle.get('id')], false)
|
||||
.setIn(['circleList', circle.get('id')], payload.circle)
|
||||
}
|
||||
|
||||
/**
|
||||
* Circle reducer
|
||||
* @param state
|
||||
* @param action
|
||||
*/
|
||||
export let circleReducer = (state: CircleState = new CircleState(), action: ICircleAction) => {
|
||||
export let circleReducer = (state = Map(new CircleState()), action: ICircleAction) => {
|
||||
const { payload } = action
|
||||
switch (action.type) {
|
||||
case CircleActionType.CLEAR_ALL_CIRCLES:
|
||||
return new CircleState()
|
||||
return Map(new CircleState())
|
||||
|
||||
case CircleActionType.ADD_CIRCLE:
|
||||
return {
|
||||
...state,
|
||||
circleList: {
|
||||
...state.circleList,
|
||||
[payload.circle.id]: {
|
||||
...payload.circle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case CircleActionType.UPDATE_CIRCLE:
|
||||
return {
|
||||
...state,
|
||||
openSetting: {
|
||||
...state.openSetting,
|
||||
[payload.circle.id]: false
|
||||
},
|
||||
circleList: {
|
||||
...state.circleList,
|
||||
[payload.circle.id]: {
|
||||
...payload.circle
|
||||
}
|
||||
}
|
||||
}
|
||||
case CircleActionType.ADD_CIRCLE: return addCircle(state, payload)
|
||||
case CircleActionType.UPDATE_CIRCLE: return updateCircle(state, payload)
|
||||
|
||||
case CircleActionType.DELETE_CIRCLE:
|
||||
let filteredDeleteCircles = {}
|
||||
Object.keys(state.circleList).map((key) => {
|
||||
if (key !== payload.circleId) {
|
||||
return _.merge(filteredDeleteCircles, { [key]: { ...state.circleList![key] } })
|
||||
}
|
||||
})
|
||||
return {
|
||||
...state,
|
||||
circleList: {
|
||||
...state.circleList,
|
||||
...filteredDeleteCircles
|
||||
}
|
||||
}
|
||||
return state
|
||||
.deleteIn(['circleList', payload.circleId])
|
||||
|
||||
case CircleActionType.ADD_LIST_CIRCLE:
|
||||
return {
|
||||
...state,
|
||||
circleList: {
|
||||
...state.circleList,
|
||||
...payload.circleList
|
||||
},
|
||||
loaded: true
|
||||
}
|
||||
return state
|
||||
.set('loaded', true)
|
||||
.mergeIn(['circleList'], payload.circleList)
|
||||
|
||||
case CircleActionType.ADD_FOLLOWING_USER:
|
||||
return {
|
||||
...state,
|
||||
userTies: {
|
||||
...state.userTies,
|
||||
[payload.userTie.userId]: {
|
||||
...payload.userTie
|
||||
}
|
||||
},
|
||||
selectedCircles: {
|
||||
...state.selectedCircles,
|
||||
[payload.userTie.userId]: payload.userTie.circleIdList
|
||||
}
|
||||
}
|
||||
const userTie: Map<string, any> = payload.userTie
|
||||
return state
|
||||
.setIn(['userTies', userTie.get('userId')], payload.userTie)
|
||||
.setIn(['selectedCircles', userTie.get('userId')], userTie.get('circleIdList'))
|
||||
|
||||
case CircleActionType.UPDATE_USER_TIE:
|
||||
return {
|
||||
...state,
|
||||
userTies: {
|
||||
...state.userTies,
|
||||
[payload.userTie.user.userId]: {
|
||||
...payload.userTie
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['userTies', payload.userTie.user.userId], payload.userTie)
|
||||
|
||||
case CircleActionType.ADD_USER_TIE_LIST:
|
||||
return {
|
||||
...state,
|
||||
userTies: {
|
||||
...state.userTies,
|
||||
...payload.userTies
|
||||
},
|
||||
selectedCircles : getSelectedCircles(payload.userTies)
|
||||
}
|
||||
return state
|
||||
.mergeIn(['userTies'], payload.userTies)
|
||||
.set('selectedCircles', getSelectedCircles(payload.userTies))
|
||||
|
||||
case CircleActionType.ADD_USER_TIED_LIST:
|
||||
return {
|
||||
...state,
|
||||
userTieds: {
|
||||
...state.userTieds,
|
||||
...payload.userTieds
|
||||
}
|
||||
}
|
||||
return state
|
||||
.mergeIn(['userTieds'], payload.userTieds)
|
||||
|
||||
case CircleActionType.DELETE_USER_FROM_CIRCLE:
|
||||
let filteredCircles: string[] = []
|
||||
Object.keys(state.userTies[payload.userId].circleIdList!).forEach((circleId) => {
|
||||
if (circleId !== payload.circleId) {
|
||||
filteredCircles.push(circleId)
|
||||
}
|
||||
})
|
||||
return {
|
||||
...state,
|
||||
userTies: {
|
||||
...state.userTies,
|
||||
[payload.userTie.user.userId]: {
|
||||
...payload.userTie,
|
||||
circleIdList: filteredCircles
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.deleteIn(['userTies', payload.userTie.user.userId, 'circleIdList', payload.circleId])
|
||||
|
||||
case CircleActionType.DELETE_FOLLOWING_USER:
|
||||
let filteredUserTies: {[userId: string]: UserTie } = {}
|
||||
return state
|
||||
.deleteIn(['userTies', payload.userId])
|
||||
.deleteIn(['selectedCircles', payload.userId])
|
||||
|
||||
Object.keys(state.userTies).forEach((userId) => {
|
||||
if (userId !== payload.userId) {
|
||||
return _.merge(filteredUserTies, { [userId]: { ...state.userTies[userId] } })
|
||||
}
|
||||
})
|
||||
return {
|
||||
...state,
|
||||
userTies: {
|
||||
...filteredUserTies
|
||||
},
|
||||
selectedCircles : getSelectedCircles(filteredUserTies)
|
||||
}
|
||||
|
||||
/**
|
||||
* User interface stuffs
|
||||
*/
|
||||
/**
|
||||
* User interface stuffs
|
||||
*/
|
||||
|
||||
case CircleActionType.CLOSE_CIRCLE_SETTINGS:
|
||||
return {
|
||||
...state,
|
||||
openSetting: {
|
||||
...state.openSetting,
|
||||
[payload.circleId]: false
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['openSetting', payload.circleId], false)
|
||||
|
||||
case CircleActionType.OPEN_CIRCLE_SETTINGS:
|
||||
return {
|
||||
...state,
|
||||
openSetting: {
|
||||
...state.openSetting,
|
||||
[payload.circleId]: true
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['openSetting', payload.circleId], true)
|
||||
|
||||
case CircleActionType.SHOW_SELECT_CIRCLE_BOX:
|
||||
return {
|
||||
...state,
|
||||
selectCircleStatus: {
|
||||
...state.selectCircleStatus,
|
||||
[payload.userId]: true
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['selectCircleStatus', payload.userId], true)
|
||||
|
||||
case CircleActionType.HIDE_SELECT_CIRCLE_BOX:
|
||||
return {
|
||||
...state,
|
||||
selectCircleStatus: {
|
||||
...state.selectCircleStatus,
|
||||
[payload.userId]: false
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['selectCircleStatus', payload.userId], false)
|
||||
|
||||
case CircleActionType.SHOW_FOLLOWING_USER_LOADING:
|
||||
return {
|
||||
...state,
|
||||
followingLoadingStatus: {
|
||||
...state.followingLoadingStatus,
|
||||
[payload.userId]: true
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['followingLoadingStatus', payload.userId], true)
|
||||
|
||||
case CircleActionType.HIDE_FOLLOWING_USER_LOADING:
|
||||
return {
|
||||
...state,
|
||||
followingLoadingStatus: {
|
||||
...state.followingLoadingStatus,
|
||||
[payload.userId]: false
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['followingLoadingStatus', payload.userId], false)
|
||||
|
||||
/**
|
||||
* User box component
|
||||
*/
|
||||
case CircleActionType.SET_SELECTED_CIRCLES_USER_BOX_COMPONENT:
|
||||
return {
|
||||
...state,
|
||||
selectedCircles: {
|
||||
...state.selectedCircles,
|
||||
[payload.userId]: payload.circleList
|
||||
}
|
||||
}
|
||||
/**
|
||||
* User box component
|
||||
*/
|
||||
return state
|
||||
.setIn(['selectedCircles', payload.userId], payload.circleList)
|
||||
|
||||
case CircleActionType.REMOVE_SELECTED_CIRCLES_USER_BOX_COMPONENT:
|
||||
return {
|
||||
...state,
|
||||
selectedCircles: {
|
||||
...state.selectedCircles,
|
||||
[payload.userId]: []
|
||||
}
|
||||
}
|
||||
/**
|
||||
* User box component
|
||||
*/
|
||||
return state
|
||||
.setIn(['selectedCircles', payload.userId], [])
|
||||
|
||||
case CircleActionType.OPEN_SELECT_CIRCLES_USER_BOX_COMPONENT:
|
||||
return {
|
||||
...state,
|
||||
openSelecteCircles: {
|
||||
...state.openSelecteCircles,
|
||||
[payload.userId]: true
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['openSelecteCircles', payload.userId], true)
|
||||
|
||||
case CircleActionType.CLOSE_SELECT_CIRCLES_USER_BOX_COMPONENT:
|
||||
return {
|
||||
...state,
|
||||
openSelecteCircles: {
|
||||
...state.openSelecteCircles,
|
||||
[payload.userId]: false
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['openSelecteCircles', payload.userId], false)
|
||||
|
||||
default:
|
||||
return state
|
||||
|
||||
@@ -260,14 +136,11 @@ export let circleReducer = (state: CircleState = new CircleState(), action: ICir
|
||||
/**
|
||||
* Map user ties selected to selected circles
|
||||
*/
|
||||
const getSelectedCircles = (userTies: {[userId: string]: UserTie }) => {
|
||||
let selectedCircles: {[userId: string]: string[]} = {}
|
||||
const getSelectedCircles = (userTies: { [userId: string]: UserTie }) => {
|
||||
let selectedCircles: Map<string, List<string>> = Map({})
|
||||
Object.keys(userTies).forEach((userId: string) => {
|
||||
const userTie = (userTies as {[userId: string]: UserTie })[userId]
|
||||
selectedCircles = {
|
||||
...selectedCircles,
|
||||
[userTie.userId!]: userTie.circleIdList!
|
||||
}
|
||||
const userTie = (userTies as { [userId: string]: UserTie })[userId]
|
||||
selectedCircles = selectedCircles.set(userTie.userId!, List(userTie.circleIdList!))
|
||||
})
|
||||
|
||||
return selectedCircles
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import { Comment } from 'src/core/domain/comments'
|
||||
|
||||
import {Map} from 'immutable'
|
||||
/**
|
||||
* Comment state
|
||||
*
|
||||
@@ -11,22 +11,16 @@ export class CommentState {
|
||||
|
||||
/**
|
||||
* The list of comments on the posts
|
||||
*
|
||||
* @type {({[postId: string]: {[commentId: string]: Comment}} | null)}
|
||||
* @memberof CommentState
|
||||
*/
|
||||
postComments: {[postId: string]: {[commentId: string]: Comment}} = {}
|
||||
postComments: Map<string, {[commentId: string]: Comment}> = Map({})
|
||||
|
||||
/**
|
||||
* Whether comment editor is open
|
||||
*/
|
||||
editorStatus: {[postId: string]: {[commentId: string]: boolean}} = {}
|
||||
editorStatus: Map<string, {[commentId: string]: boolean}> = Map({})
|
||||
|
||||
/**
|
||||
* If the comments are loaded {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof CommentState
|
||||
*/
|
||||
loaded: Boolean = false
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// - Import react components
|
||||
import moment from 'moment/moment'
|
||||
import _ from 'lodash'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import domain
|
||||
import { User } from 'src/core/domain/users'
|
||||
@@ -17,96 +18,38 @@ import { ICommentAction } from './ICommentAction'
|
||||
* @param state
|
||||
* @param action
|
||||
*/
|
||||
export let commentReducer = (state: CommentState = new CommentState(), action: ICommentAction) => {
|
||||
export let commentReducer = (state = Map(new CommentState()), action: ICommentAction) => {
|
||||
let { payload } = action
|
||||
switch (action.type) {
|
||||
|
||||
/* _____________ CRUD _____________ */
|
||||
case CommentActionType.ADD_COMMENT:
|
||||
return {
|
||||
...state,
|
||||
postComments: {
|
||||
...state.postComments,
|
||||
[payload.postId]: {
|
||||
...state.postComments![payload.postId],
|
||||
[payload.id]: {
|
||||
...payload,
|
||||
editorStatus: false
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['postComments', payload.postId, payload.id], payload)
|
||||
|
||||
}
|
||||
}
|
||||
case CommentActionType.ADD_COMMENT_LIST:
|
||||
return {
|
||||
...state,
|
||||
postComments: {
|
||||
...state.postComments,
|
||||
...payload
|
||||
},
|
||||
loaded: true
|
||||
}
|
||||
case CommentActionType.UPDATE_COMMENT:
|
||||
const {comment} = payload
|
||||
return {
|
||||
...state,
|
||||
postComments: {
|
||||
...state.postComments,
|
||||
[comment.postId]: {
|
||||
...state.postComments![comment.postId],
|
||||
[comment.id]: {
|
||||
...state.postComments![comment.postId][comment.id],
|
||||
text: comment.text,
|
||||
editorStatus: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case CommentActionType.DELETE_COMMENT:
|
||||
if (!state.postComments![payload.postId]) {
|
||||
return state
|
||||
}
|
||||
let parsedComments = {}
|
||||
Object.keys(state.postComments![payload.postId]).map((id) => {
|
||||
if (id !== payload.id) {
|
||||
_.merge(parsedComments, { [id]: { ...state.postComments![payload.postId][id] } })
|
||||
}
|
||||
return state
|
||||
.mergeIn(['postComments'], payload)
|
||||
.set('loaded', true)
|
||||
|
||||
case CommentActionType.UPDATE_COMMENT:
|
||||
const { comment } = payload
|
||||
return state
|
||||
.updateIn(['postComments', comment.postId, comment.id, 'text'], (text: string) => comment.text)
|
||||
|
||||
case CommentActionType.DELETE_COMMENT:
|
||||
return state.deleteIn(['postComments', payload.postId, payload.id])
|
||||
|
||||
})
|
||||
return {
|
||||
...state,
|
||||
postComments: {
|
||||
...state.postComments,
|
||||
[payload.postId]: {
|
||||
...parsedComments
|
||||
}
|
||||
}
|
||||
}
|
||||
case CommentActionType.CLOSE_COMMENT_EDITOR:
|
||||
return {
|
||||
...state,
|
||||
editorStatus: {
|
||||
...state.editorStatus,
|
||||
[payload.postId]: {
|
||||
...state.editorStatus![payload.postId],
|
||||
[payload.id]: false
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['editorStatus', payload.postId, payload.id], false)
|
||||
|
||||
case CommentActionType.OPEN_COMMENT_EDITOR:
|
||||
return {
|
||||
...state,
|
||||
editorStatus: {
|
||||
...state.editorStatus,
|
||||
[payload.postId]: {
|
||||
...state.editorStatus![payload.postId],
|
||||
[payload.id]: true
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['editorStatus', payload.postId, payload.id], true)
|
||||
|
||||
case CommentActionType.CLEAR_ALL_DATA_COMMENT:
|
||||
return new CommentState()
|
||||
return Map(new CommentState())
|
||||
default:
|
||||
return state
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Map, fromJS, List } from 'immutable'
|
||||
/**
|
||||
* Global state
|
||||
*
|
||||
@@ -15,13 +16,10 @@ export class GlobalState {
|
||||
* }}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
progress: {
|
||||
percent: number
|
||||
visible: boolean
|
||||
} = {
|
||||
progress = Map({
|
||||
percent: 0,
|
||||
visible: false
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* If loading is enabled {true} or not false
|
||||
@@ -122,7 +120,7 @@ export class GlobalState {
|
||||
* @type {*}
|
||||
* @memberof IGlobalState
|
||||
*/
|
||||
temp: any = {
|
||||
caller: []
|
||||
}
|
||||
temp: any = Map({
|
||||
caller: List()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,112 +3,86 @@ import { GlobalActionType } from 'constants/globalActionType'
|
||||
|
||||
import { GlobalState } from './GlobalState'
|
||||
import { IGlobalAction } from './IGlobalAction'
|
||||
import { Map, fromJS } from 'immutable'
|
||||
|
||||
/**
|
||||
* Global reducer
|
||||
* @param {object} state
|
||||
* @param {object} action
|
||||
*/
|
||||
export const globalReducer = (state: GlobalState = new GlobalState(), action: IGlobalAction) => {
|
||||
export const globalReducer = (state = Map(new GlobalState()), action: IGlobalAction) => {
|
||||
const { payload } = action
|
||||
switch (action.type) {
|
||||
case GlobalActionType.PROGRESS_CHANGE:
|
||||
return {
|
||||
...state,
|
||||
progress: {
|
||||
...state.progress,
|
||||
percent: payload.percent,
|
||||
visible: payload.visible
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['progress', 'percent'], payload.percent)
|
||||
.setIn(['progress', 'visible'], payload.visible)
|
||||
|
||||
case GlobalActionType.DEFAULT_DATA_DISABLE:
|
||||
return {
|
||||
...state,
|
||||
defaultLoadDataStatus: false
|
||||
}
|
||||
return state
|
||||
.set('defaultLoadDataStatus', false)
|
||||
|
||||
case GlobalActionType.DEFAULT_DATA_ENABLE:
|
||||
return {
|
||||
...state,
|
||||
defaultLoadDataStatus: true
|
||||
}
|
||||
return state
|
||||
.set('defaultLoadDataStatus', true)
|
||||
|
||||
case GlobalActionType.SHOW_MESSAGE_GLOBAL:
|
||||
return {
|
||||
...state,
|
||||
message: action.payload,
|
||||
messageOpen: true
|
||||
}
|
||||
return state
|
||||
.set('message', action.payload)
|
||||
.set('messageOpen', true)
|
||||
|
||||
case GlobalActionType.SHOW_NORMAL_MESSAGE_GLOBAL:
|
||||
return {
|
||||
...state,
|
||||
message: action.payload,
|
||||
messageOpen: true
|
||||
}
|
||||
return state
|
||||
.set('message', action.payload)
|
||||
.set('messageOpen', true)
|
||||
|
||||
case GlobalActionType.HIDE_MESSAGE_GLOBAL:
|
||||
return {
|
||||
...state,
|
||||
message: '',
|
||||
messageOpen: false,
|
||||
messageColor: ''
|
||||
}
|
||||
return state
|
||||
.set('message', action.payload)
|
||||
.set('messageOpen', false)
|
||||
.set('messageColor', '')
|
||||
|
||||
case GlobalActionType.SET_HEADER_TITLE:
|
||||
return {
|
||||
...state,
|
||||
headerTitle: action.payload
|
||||
}
|
||||
return state
|
||||
.set('headerTitle', action.payload)
|
||||
|
||||
case GlobalActionType.SHOW_SEND_FEEDBACK:
|
||||
return {
|
||||
...state,
|
||||
sendFeedbackStatus: true
|
||||
}
|
||||
return state
|
||||
.set('sendFeedbackStatus', true)
|
||||
|
||||
case GlobalActionType.HIDE_SEND_FEEDBACK:
|
||||
return {
|
||||
...state,
|
||||
sendFeedbackStatus: false
|
||||
}
|
||||
return state
|
||||
.set('sendFeedbackStatus', false)
|
||||
|
||||
case GlobalActionType.HIDE_TOP_LOADING:
|
||||
const queueTopLoading = state.topLoadingQueue > 0 ? (state.topLoadingQueue - 1) : 0
|
||||
return {
|
||||
...state,
|
||||
topLoadingQueue: queueTopLoading,
|
||||
showTopLoading: (queueTopLoading > 0 ? true : false)
|
||||
const queueTopLoading = Number(state.get('topLoadingQueue')) > 0 ? (Number(state.get('topLoadingQueue')) - 1) : 0
|
||||
return state
|
||||
.set('topLoadingQueue', queueTopLoading)
|
||||
.set('showTopLoading', (queueTopLoading > 0 ? true : false))
|
||||
|
||||
}
|
||||
case GlobalActionType.SHOW_TOP_LOADING:
|
||||
return {
|
||||
...state,
|
||||
topLoadingQueue: (state.topLoadingQueue + 1),
|
||||
showTopLoading: true
|
||||
}
|
||||
case GlobalActionType.HIDE_MASTER_LOADING:
|
||||
const queueMasterLoading = state.masterLoadingQueue > 0 ? (state.masterLoadingQueue - 1) : 0
|
||||
return {
|
||||
...state,
|
||||
masterLoadingQueue: queueMasterLoading,
|
||||
showMasterLoading: (queueMasterLoading > 0 ? true : false)
|
||||
return state
|
||||
.set('topLoadingQueue', (Number(state.get('topLoadingQueue')) + 1))
|
||||
.set('showTopLoading', true)
|
||||
|
||||
case GlobalActionType.HIDE_MASTER_LOADING:
|
||||
const queueMasterLoading = Number(state.get('masterLoadingQueue')) > 0 ? (Number(state.get('masterLoadingQueue')) - 1) : 0
|
||||
return state
|
||||
.set('masterLoadingQueue', queueMasterLoading)
|
||||
.set('showMasterLoading', (queueMasterLoading > 0 ? true : false))
|
||||
|
||||
}
|
||||
case GlobalActionType.SHOW_MASTER_LOADING:
|
||||
return {
|
||||
...state,
|
||||
masterLoadingQueue: (state.masterLoadingQueue + 1),
|
||||
showMasterLoading: true
|
||||
}
|
||||
return state
|
||||
.set('masterLoadingQueue', Number(state.get('masterLoadingQueue')) + 1)
|
||||
.set('showMasterLoading', true)
|
||||
|
||||
case GlobalActionType.TEMP:
|
||||
return {
|
||||
...state,
|
||||
temp: {
|
||||
...state.temp,
|
||||
caller: [
|
||||
...state.temp.caller,
|
||||
payload.caller
|
||||
]
|
||||
}
|
||||
}
|
||||
case GlobalActionType.CLEAR_ALL_GLOBAL:
|
||||
return {
|
||||
...state,
|
||||
sendFeedbackStatus: false,
|
||||
}
|
||||
return state
|
||||
.mergeIn(['temp', 'caller'], fromJS([payload.caller]))
|
||||
|
||||
case GlobalActionType.CLEAR_ALL_GLOBAL:
|
||||
return state
|
||||
.set('sendFeedbackStatus', false)
|
||||
|
||||
default:
|
||||
return state
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Image } from 'src/core/domain/imageGallery'
|
||||
import {Map, Collection, List} from 'immutable'
|
||||
|
||||
/**
|
||||
* ImageGallery state
|
||||
@@ -18,49 +19,31 @@ export class ImageGalleryState {
|
||||
|
||||
/**
|
||||
* The list of image
|
||||
*
|
||||
* @type {(Image[] | null)}
|
||||
* @memberof ImageGalleryState
|
||||
*/
|
||||
images: Image[] = []
|
||||
images: List<Image> = List()
|
||||
|
||||
/**
|
||||
* Selected image name
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImageGalleryState
|
||||
*/
|
||||
selectImage: string = ''
|
||||
|
||||
/**
|
||||
* Selected image address
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ImageGalleryState
|
||||
*/
|
||||
selectURL: string = ''
|
||||
|
||||
/**
|
||||
* If image gallery is loaded {true} or not false
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof ImageGalleryState
|
||||
*/
|
||||
loaded: Boolean = false
|
||||
|
||||
/**
|
||||
* Images address list
|
||||
*
|
||||
* @type {*}
|
||||
* @memberof ImageGalleryState
|
||||
*/
|
||||
imageURLList: any = {}
|
||||
|
||||
/**
|
||||
* Store image requested
|
||||
*
|
||||
* @type {*}
|
||||
* @memberof ImageGalleryState
|
||||
*/
|
||||
imageRequests: any = {}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// - Import react components
|
||||
import _ from 'lodash'
|
||||
import { Map, List } from 'immutable'
|
||||
|
||||
// - Import domain
|
||||
import { User } from 'src/core/domain/users'
|
||||
@@ -14,52 +15,36 @@ import { ImageGalleryState } from './ImageGalleryState'
|
||||
/**
|
||||
* Image gallery reducer
|
||||
*/
|
||||
export let imageGalleryReducer = (state: ImageGalleryState = new ImageGalleryState(), action: IImageGalleryAction) => {
|
||||
export let imageGalleryReducer = (state = Map(new ImageGalleryState()), action: IImageGalleryAction) => {
|
||||
const { payload } = action
|
||||
|
||||
switch (action.type) {
|
||||
/* ----------------- CRUD ----------------- */
|
||||
case ImageGalleryActionType.ADD_IMAGE_GALLERY:
|
||||
return {
|
||||
...state,
|
||||
images: [...state.images!, payload]
|
||||
}
|
||||
return state
|
||||
.mergeIn(['images'], List([payload]))
|
||||
|
||||
case ImageGalleryActionType.ADD_IMAGE_LIST_GALLERY:
|
||||
return {
|
||||
...state,
|
||||
images: [...payload],
|
||||
loaded: true
|
||||
}
|
||||
return state
|
||||
.set('images', List(payload))
|
||||
.set('loaded', true)
|
||||
|
||||
case ImageGalleryActionType.DELETE_IMAGE:
|
||||
return {
|
||||
...state,
|
||||
images: [
|
||||
...state.images!.filter((item: Image) => {
|
||||
return item.id !== payload
|
||||
})
|
||||
]
|
||||
}
|
||||
return state
|
||||
.update('images', (images: List<Image>) => {
|
||||
return images.filter((image) => image!.id !== payload)
|
||||
})
|
||||
|
||||
case ImageGalleryActionType.SET_IMAGE_URL:
|
||||
return {
|
||||
...state,
|
||||
imageURLList: {
|
||||
...state.imageURLList,
|
||||
[payload.name]: payload.url
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['imageURLList', payload.name], payload.url)
|
||||
|
||||
case ImageGalleryActionType.SEND_IMAGE_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
imageRequests: [
|
||||
...state.imageRequests,
|
||||
payload
|
||||
]
|
||||
}
|
||||
return state
|
||||
.mergeIn(['imageRequests'], payload)
|
||||
|
||||
case ImageGalleryActionType.CLEAT_ALL_DATA_IMAGE_GALLERY:
|
||||
return new ImageGalleryState()
|
||||
return Map(new ImageGalleryState())
|
||||
|
||||
default:
|
||||
return state
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Notification } from 'src/core/domain/notifications'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
/**
|
||||
* Notification state
|
||||
@@ -10,17 +11,11 @@ export class NotificationState {
|
||||
|
||||
/**
|
||||
* The list of users notification
|
||||
*
|
||||
* @type {({[userId: string]: {[notificationId: string]: Notification}} | null)}
|
||||
* @memberof NotificationState
|
||||
*/
|
||||
userNotifies: {[userId: string]: {[notificationId: string]: Notification}} = {}
|
||||
userNotifies: Map<string, Map<string, any>> = Map({})
|
||||
|
||||
/**
|
||||
* If user notifications are loaded {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof NotificationState
|
||||
*/
|
||||
loaded: Boolean = false
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// - Import react components
|
||||
import moment from 'moment/moment'
|
||||
import _ from 'lodash'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import domain
|
||||
import { Notification } from 'src/core/domain/notifications'
|
||||
@@ -16,7 +17,7 @@ import { INotificationAction } from './INotificationAction'
|
||||
* @param {object} state
|
||||
* @param {object} action
|
||||
*/
|
||||
export let notificationReducer = (state: NotificationState = new NotificationState(), action: INotificationAction) => {
|
||||
export let notificationReducer = (state = Map(new NotificationState()), action: INotificationAction) => {
|
||||
let { payload } = action
|
||||
switch (action.type) {
|
||||
|
||||
@@ -25,44 +26,21 @@ export let notificationReducer = (state: NotificationState = new NotificationSta
|
||||
return state
|
||||
|
||||
case NotificationActionType.ADD_NOTIFY_LIST:
|
||||
return {
|
||||
...state,
|
||||
userNotifies: {
|
||||
...payload
|
||||
},
|
||||
loaded: true
|
||||
}
|
||||
return state
|
||||
.set('userNotifies', payload)
|
||||
.set('loaded', true)
|
||||
|
||||
case NotificationActionType.SEEN_NOTIFY:
|
||||
return {
|
||||
...state,
|
||||
userNotifies: {
|
||||
...state.userNotifies,
|
||||
[payload]: {
|
||||
...state.userNotifies![payload],
|
||||
isSeen: true
|
||||
}
|
||||
},
|
||||
loaded: true
|
||||
}
|
||||
return state
|
||||
.setIn(['userNotifies', payload, 'isSeen'], true)
|
||||
.set('loaded', true)
|
||||
|
||||
case NotificationActionType.DELETE_NOTIFY:
|
||||
let parsedNotifies = {}
|
||||
Object.keys(state.userNotifies!).map((id) => {
|
||||
if (id !== payload) {
|
||||
_.merge(parsedNotifies, { [id]: { ...state.userNotifies![id] } })
|
||||
}
|
||||
|
||||
})
|
||||
return {
|
||||
...state,
|
||||
userNotifies: {
|
||||
...parsedNotifies
|
||||
}
|
||||
}
|
||||
return state
|
||||
.deleteIn(['userNotifies', payload])
|
||||
|
||||
case NotificationActionType.CLEAR_ALL_DATA_NOTIFY:
|
||||
return new NotificationState()
|
||||
return Map(new NotificationState())
|
||||
|
||||
default:
|
||||
return state
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Post } from 'src/core/domain/posts'
|
||||
import { Map, fromJS, List } from 'immutable'
|
||||
|
||||
/**
|
||||
* Post state
|
||||
@@ -14,7 +15,7 @@ export class PostState {
|
||||
* @type {*}
|
||||
* @memberof PostState
|
||||
*/
|
||||
userPosts: any = {}
|
||||
userPosts = Map({})
|
||||
|
||||
/**
|
||||
* If user posts are loaded {true} or not {false}
|
||||
@@ -27,12 +28,12 @@ export class PostState {
|
||||
/**
|
||||
* Stream data storage
|
||||
*/
|
||||
stream?: {hasMoreData: boolean, lastPageRequest: number, lastPostId: string} =
|
||||
{hasMoreData: true, lastPageRequest: -1, lastPostId: ''}
|
||||
stream?: Map<string,any> =
|
||||
Map({hasMoreData: true, lastPageRequest: -1, lastPostId: ''})
|
||||
|
||||
/**
|
||||
* Profile posts data storage
|
||||
*/
|
||||
profile?: {[userId: string]: {hasMoreData: boolean, lastPageRequest: number, lastPostId: string}} =
|
||||
{}
|
||||
profile?: Map<string, any> =
|
||||
Map({})
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import moment from 'moment/moment'
|
||||
import _ from 'lodash'
|
||||
import { Reducer, Action } from 'redux'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import action types
|
||||
import { PostActionType } from 'constants/postActionType'
|
||||
@@ -11,167 +12,94 @@ import { IPostAction } from './IPostAction'
|
||||
import { Post } from 'src/core/domain/posts/post'
|
||||
import CommonAPI from 'src/api/CommonAPI'
|
||||
|
||||
const updatePost = (state: any, payload: any) => {
|
||||
const post: Map<string, any> = payload.post
|
||||
const updatePostOwnerId = post.get('ownerUserId')
|
||||
const updatePostId = post.get('id')
|
||||
return state
|
||||
.setIn(['userPosts', updatePostOwnerId, updatePostId], Map(post))
|
||||
}
|
||||
|
||||
const updatePostComments = (state: any, payload: any) => {
|
||||
const post: Map<string, any> = payload.post
|
||||
const updatePostOwnerId = post.get('ownerUserId')
|
||||
const updatePostId = post.get('id')
|
||||
return state
|
||||
.setIn(['userPosts', updatePostOwnerId, updatePostId, 'comments'], post.get('comments'))
|
||||
}
|
||||
|
||||
const updatePostVotes = (state: any, payload: any) => {
|
||||
const post: Map<string, any> = payload.post
|
||||
const updatePostOwnerId = post.get('ownerUserId')
|
||||
const updatePostId = post.get('id')
|
||||
return state
|
||||
.setIn(['userPosts', updatePostOwnerId, updatePostId, 'votes'], post.get('votes'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Post reducer
|
||||
* @param {object} state
|
||||
* @param {object} action
|
||||
*/
|
||||
export let postReducer = (state: PostState = new PostState(), action: IPostAction) => {
|
||||
export let postReducer = (state = Map(new PostState()), action: IPostAction) => {
|
||||
const { payload } = action
|
||||
switch (action.type) {
|
||||
case PostActionType.CLEAR_ALL_DATA_POST:
|
||||
return new PostState()
|
||||
return Map(new PostState())
|
||||
|
||||
case PostActionType.ADD_IMAGE_POST:
|
||||
return {
|
||||
...state,
|
||||
userPosts: {
|
||||
...state.userPosts,
|
||||
[payload.uid]: {
|
||||
...state.userPosts[payload.uid],
|
||||
[payload.post.id]: { ...payload.post }
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['userPosts', payload.uid, payload.post.id], Map(payload.post))
|
||||
|
||||
case PostActionType.ADD_POST:
|
||||
return {
|
||||
...state,
|
||||
userPosts: {
|
||||
...state.userPosts,
|
||||
[payload.uid]: {
|
||||
...state.userPosts[payload.uid],
|
||||
[payload.post.id]: { ...payload.post }
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['userPosts', payload.uid, payload.post.id], Map(payload.post))
|
||||
|
||||
case PostActionType.UPDATE_POST:
|
||||
const post: Post = payload.post
|
||||
return {
|
||||
...state,
|
||||
userPosts: {
|
||||
...state.userPosts,
|
||||
[post.ownerUserId!]: {
|
||||
...state.userPosts[post.ownerUserId!],
|
||||
[payload.post.id]: {
|
||||
...payload.post,
|
||||
comments: post.comments,
|
||||
votes: post.votes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case PostActionType.UPDATE_POST: return updatePost(state, payload)
|
||||
case PostActionType.UPDATE_POST_COMMENTS: return updatePostComments(state, payload)
|
||||
case PostActionType.UPDATE_POST_VOTES: return updatePostVotes(state, payload)
|
||||
|
||||
case PostActionType.DELETE_POST:
|
||||
let filteredPosts = {}
|
||||
Object.keys(state.userPosts[payload.uid]).map((key) => {
|
||||
if (key !== payload.id) {
|
||||
return _.merge(filteredPosts, { [key]: { ...state.userPosts[payload.uid][key] } })
|
||||
}
|
||||
})
|
||||
return {
|
||||
...state,
|
||||
userPosts: {
|
||||
...state.userPosts,
|
||||
[payload.uid]: {
|
||||
...filteredPosts
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.deleteIn(['userPosts', payload.uid, payload.id])
|
||||
|
||||
case PostActionType.ADD_LIST_POST:
|
||||
const newUserPosts = payload.userPosts as { [userId: string]: { [postId: string]: Post } }
|
||||
const mergedObject = _.merge(state.userPosts, newUserPosts)
|
||||
return {
|
||||
...state,
|
||||
userPosts: {
|
||||
...mergedObject
|
||||
},
|
||||
loaded: true
|
||||
return state
|
||||
.mergeDeepIn(['userPosts'], payload.userPosts)
|
||||
.set('loaded', true)
|
||||
|
||||
}
|
||||
case PostActionType.HAS_MORE_DATA_STREAM:
|
||||
return {
|
||||
...state,
|
||||
stream: {
|
||||
...state.stream,
|
||||
hasMoreData: true
|
||||
}
|
||||
return state
|
||||
.setIn(['stream', 'hasMoreData'], true)
|
||||
|
||||
}
|
||||
case PostActionType.NOT_MORE_DATA_STREAM:
|
||||
return {
|
||||
...state,
|
||||
stream: {
|
||||
...state.stream,
|
||||
hasMoreData: false
|
||||
}
|
||||
|
||||
}
|
||||
return state
|
||||
.setIn(['stream', 'hasMoreData'], false)
|
||||
|
||||
case PostActionType.REQUEST_PAGE_STREAM:
|
||||
return {
|
||||
...state,
|
||||
stream: {
|
||||
...state.stream,
|
||||
lastPageRequest: payload.page
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['stream', 'lastPageRequest'], payload.page)
|
||||
|
||||
case PostActionType.LAST_POST_STREAM:
|
||||
return {
|
||||
...state,
|
||||
stream: {
|
||||
...state.stream,
|
||||
lastPostId: payload.lastPostId
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['stream', 'lastPostId'], payload.lastPostId)
|
||||
|
||||
case PostActionType.HAS_MORE_DATA_PROFILE:
|
||||
return {
|
||||
...state,
|
||||
profile: {
|
||||
...state.profile,
|
||||
hasMoreData: true
|
||||
}
|
||||
return state
|
||||
.setIn(['profile', 'hasMoreData'], true)
|
||||
|
||||
}
|
||||
case PostActionType.NOT_MORE_DATA_PROFILE:
|
||||
return {
|
||||
...state,
|
||||
profile: {
|
||||
...state.profile,
|
||||
[payload.userId]: {
|
||||
...state.profile![payload.userId],
|
||||
hasMoreData: false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return state
|
||||
.setIn(['profile', payload.userId, 'hasMoreData'], false)
|
||||
|
||||
case PostActionType.REQUEST_PAGE_PROFILE:
|
||||
return {
|
||||
...state,
|
||||
profile: {
|
||||
...state.profile,
|
||||
[payload.userId]: {
|
||||
...state.profile![payload.userId],
|
||||
lastPageRequest: payload.page
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['profile', payload.userId, 'lastPageRequest'], payload.page)
|
||||
|
||||
case PostActionType.LAST_POST_PROFILE:
|
||||
return {
|
||||
...state,
|
||||
profile: {
|
||||
...state.profile,
|
||||
[payload.userId]: {
|
||||
...state.profile![payload.userId],
|
||||
lastPostId: payload.lastPostId
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['profile', payload.userId, 'lastPostId'], payload.lastPostId)
|
||||
|
||||
default:
|
||||
return state
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const getPost = (state: any, userId: string, postId: string) => {
|
||||
return (state.post.userPosts && state.post.userPosts[userId] && state.post.userPosts[userId][postId])
|
||||
? state.post.userPosts[userId][postId]
|
||||
: null
|
||||
import {Map} from 'immutable'
|
||||
|
||||
const getPost = (state: Map<string, any>, userId: string, postId: string) => {
|
||||
return state.getIn(['post', 'userPosts', userId, postId])
|
||||
}
|
||||
|
||||
export const postSelector = {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as redux from 'redux'
|
||||
import { localeReducer as locale } from 'react-localize-redux'
|
||||
import {
|
||||
combineReducers
|
||||
} from 'redux-immutable'
|
||||
|
||||
// - Import reducers
|
||||
import { authorizeReducer } from './authorize'
|
||||
@@ -15,7 +17,7 @@ import { serverReducer } from './server'
|
||||
import { routerReducer, routerMiddleware } from 'react-router-redux'
|
||||
|
||||
// - Reducers
|
||||
export const rootReducer = redux.combineReducers({
|
||||
export const rootReducer = combineReducers({
|
||||
locale,
|
||||
imageGallery: imageGalleryReducer,
|
||||
post: postReducer,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ServerRequestModel } from 'src/models/server'
|
||||
import {Map} from 'immutable'
|
||||
|
||||
/**
|
||||
* Server state
|
||||
@@ -12,5 +13,5 @@ export class ServerState {
|
||||
* The list of posts server
|
||||
* @memberof ServerState
|
||||
*/
|
||||
request: {[requestId: string]: ServerRequestModel} | null = {}
|
||||
request: Map<string, ServerRequestModel> = Map({})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// - Import react components
|
||||
import _ from 'lodash'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import action types
|
||||
import { ServerActionType } from 'constants/serverActionType'
|
||||
@@ -16,61 +17,30 @@ import { ServerRequestStatusType } from 'store/actions/serverRequestStatusType'
|
||||
* @param {object} state
|
||||
* @param {object} action
|
||||
*/
|
||||
export let serverReducer = (state: ServerState = new ServerState(), action: IServerAction) => {
|
||||
export let serverReducer = (state = Map(new ServerState()), action: IServerAction) => {
|
||||
let { payload } = action
|
||||
const request = (payload ? payload.request : {}) as ServerRequestModel
|
||||
switch (action.type) {
|
||||
|
||||
/* _____________ CRUD _____________ */
|
||||
case ServerActionType.ADD_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
request: {
|
||||
...state.request,
|
||||
[request.id]: {
|
||||
...request
|
||||
}
|
||||
}
|
||||
}
|
||||
case ServerActionType.DELETE_REQUEST:
|
||||
let parsedRequests = {}
|
||||
Object.keys(state.request!).forEach((id) => {
|
||||
if (id !== request.id) {
|
||||
_.merge(parsedRequests, { [id]: { ...state.request![id] } })
|
||||
}
|
||||
return state
|
||||
.setIn(['request', request.id], request)
|
||||
|
||||
})
|
||||
return {
|
||||
...state,
|
||||
request: parsedRequests
|
||||
}
|
||||
case ServerActionType.DELETE_REQUEST:
|
||||
return state
|
||||
.deleteIn(['request', request.id])
|
||||
|
||||
case ServerActionType.ERROR_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
request: {
|
||||
...state.request,
|
||||
[request.id]: {
|
||||
...state.request![request.id],
|
||||
status: ServerRequestStatusType.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['request', request.id, 'status'], ServerRequestStatusType.Error)
|
||||
|
||||
case ServerActionType.OK_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
request: {
|
||||
...state.request,
|
||||
[request.id]: {
|
||||
...state.request![request.id],
|
||||
status: ServerRequestStatusType.OK
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['request', request.id, 'status'], ServerRequestStatusType.OK)
|
||||
|
||||
case ServerActionType.CLEAR_ALL_DATA_REQUEST:
|
||||
return new ServerState()
|
||||
return Map(new ServerState())
|
||||
|
||||
default:
|
||||
return state
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { User,Profile } from 'src/core/domain/users'
|
||||
import { Map, fromJS, List } from 'immutable'
|
||||
|
||||
/**
|
||||
* User state
|
||||
@@ -9,31 +10,21 @@ import { User,Profile } from 'src/core/domain/users'
|
||||
export class UserState {
|
||||
/**
|
||||
* The list of users information
|
||||
*
|
||||
* @type {({[userId: string]: Profile} | null)}
|
||||
* @memberof UserState
|
||||
*/
|
||||
info: {[userId: string]: Profile} = {}
|
||||
info: Map<string, Profile> = Map({})
|
||||
|
||||
/**
|
||||
* If users profile are loaded
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof UserState
|
||||
*/
|
||||
loaded: Boolean = false
|
||||
|
||||
/**
|
||||
* If edit profile is open {true} or not {false}
|
||||
*
|
||||
* @type {Boolean}
|
||||
* @memberof UserState
|
||||
*/
|
||||
openEditProfile: Boolean = false
|
||||
|
||||
/**
|
||||
* People data storage
|
||||
*/
|
||||
people?: {hasMoreData: boolean, lastPageRequest: number, lastUserId: string} =
|
||||
{hasMoreData: true, lastPageRequest: -1, lastUserId: ''}
|
||||
people?: Map<string, any> = Map({hasMoreData: true, lastPageRequest: -1, lastUserId: ''})
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// - Import action types
|
||||
import { UserActionType } from 'constants/userActionType'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import domain
|
||||
import { User,Profile } from 'src/core/domain/users'
|
||||
import { User, Profile } from 'src/core/domain/users'
|
||||
|
||||
import { UserState } from './UserState'
|
||||
import { IUserAction } from './IUserAction'
|
||||
@@ -10,101 +11,52 @@ import { IUserAction } from './IUserAction'
|
||||
/**
|
||||
* User reducer
|
||||
*/
|
||||
export let userReducer = (state: UserState = new UserState(), action: IUserAction) => {
|
||||
export let userReducer = (state = Map(new UserState()), action: IUserAction) => {
|
||||
const { payload } = action
|
||||
switch (action.type) {
|
||||
case UserActionType.USER_INFO:
|
||||
return {
|
||||
...state,
|
||||
info: {
|
||||
...state.info,
|
||||
[payload.uid]: {
|
||||
...payload.info
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['info', payload.uid], payload.info)
|
||||
|
||||
case UserActionType.ADD_USER_INFO:
|
||||
return {
|
||||
...state,
|
||||
info: {
|
||||
...state.info,
|
||||
[payload.uid]: {
|
||||
...payload.info
|
||||
}
|
||||
},
|
||||
loaded: true
|
||||
}
|
||||
return state
|
||||
.setIn(['info', payload.uid], payload.info)
|
||||
.set('loaded', true)
|
||||
|
||||
case UserActionType.ADD_PEOPLE_INFO:
|
||||
return {
|
||||
...state,
|
||||
info: {
|
||||
...state.info,
|
||||
...payload
|
||||
}
|
||||
}
|
||||
return state
|
||||
.mergeIn(['info'], payload)
|
||||
|
||||
case UserActionType.UPDATE_USER_INFO:
|
||||
return {
|
||||
...state,
|
||||
info: {
|
||||
...state.info,
|
||||
[payload.uid]: {
|
||||
...state.info![payload.uid],
|
||||
...payload.info
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.mergeIn(['info', payload.uid], payload.info)
|
||||
|
||||
case UserActionType.CLEAR_ALL_DATA_USER:
|
||||
return new UserState()
|
||||
return Map(new UserState())
|
||||
|
||||
case UserActionType.CLOSE_EDIT_PROFILE:
|
||||
return {
|
||||
...state,
|
||||
openEditProfile: false
|
||||
}
|
||||
return state
|
||||
.set('openEditProfile', false)
|
||||
|
||||
case UserActionType.OPEN_EDIT_PROFILE:
|
||||
return {
|
||||
...state,
|
||||
openEditProfile: true
|
||||
}
|
||||
case UserActionType.HAS_MORE_DATA_PEOPLE:
|
||||
return {
|
||||
...state,
|
||||
people: {
|
||||
...state.people,
|
||||
hasMoreData: true
|
||||
}
|
||||
return state
|
||||
.set('openEditProfile', true)
|
||||
|
||||
case UserActionType.HAS_MORE_DATA_PEOPLE:
|
||||
return state
|
||||
.setIn(['people', 'hasMoreData'], true)
|
||||
|
||||
}
|
||||
case UserActionType.NOT_MORE_DATA_PEOPLE:
|
||||
return {
|
||||
...state,
|
||||
people: {
|
||||
...state.people,
|
||||
hasMoreData: false
|
||||
}
|
||||
|
||||
}
|
||||
return state
|
||||
.setIn(['people', 'hasMoreData'], false)
|
||||
|
||||
case UserActionType.REQUEST_PAGE_PEOPLE:
|
||||
return {
|
||||
...state,
|
||||
people: {
|
||||
...state.people,
|
||||
lastPageRequest: payload.page
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['people', 'lastPageRequest'], payload.page)
|
||||
|
||||
case UserActionType.LAST_USER_PEOPLE:
|
||||
return {
|
||||
...state,
|
||||
people: {
|
||||
...state.people,
|
||||
lastUserId: payload.lastUserId
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['people', 'lastUserId'], payload.lastUserId)
|
||||
|
||||
default:
|
||||
return state
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// - Import react components
|
||||
import moment from 'moment/moment'
|
||||
import _ from 'lodash'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
// - Import action types
|
||||
import { VoteActionType } from 'constants/voteActionType'
|
||||
@@ -16,56 +17,26 @@ import { IVoteAction } from './IVoteAction'
|
||||
* @param {object} state
|
||||
* @param {object} action
|
||||
*/
|
||||
export let voteReducer = (state: VoteState = new VoteState(), action: IVoteAction) => {
|
||||
export let voteReducer = (state = Map(new VoteState()), action: IVoteAction) => {
|
||||
let { payload } = action
|
||||
switch (action.type) {
|
||||
|
||||
/* _____________ CRUD _____________ */
|
||||
case VoteActionType.ADD_VOTE:
|
||||
return {
|
||||
...state,
|
||||
postVotes: {
|
||||
...state.postVotes,
|
||||
[payload.postId]: {
|
||||
...state.postVotes![payload.postId],
|
||||
[payload.userId]: {
|
||||
...payload
|
||||
}
|
||||
}
|
||||
return state
|
||||
.setIn(['postVotes', payload.postId, payload.userId], payload)
|
||||
|
||||
}
|
||||
}
|
||||
case VoteActionType.ADD_VOTE_LIST:
|
||||
return {
|
||||
...state,
|
||||
postVotes: {
|
||||
...payload
|
||||
},
|
||||
loaded: true
|
||||
}
|
||||
return state
|
||||
.set('postVotes', payload)
|
||||
.set('loaded', true)
|
||||
|
||||
case VoteActionType.DELETE_VOTE:
|
||||
let parsedVotes = {}
|
||||
if (state.postVotes![payload.postId]) {
|
||||
Object.keys(state.postVotes![payload.postId]).map((id) => {
|
||||
if (id !== payload.userId) {
|
||||
_.merge(parsedVotes, { [id]: { ...state.postVotes![payload.postId][id] } })
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
postVotes: {
|
||||
...state.postVotes,
|
||||
[payload.postId]: {
|
||||
...parsedVotes
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
.deleteIn(['postVotes', payload.postId, payload.userId])
|
||||
|
||||
case VoteActionType.CLEAR_ALL_DATA_VOTE:
|
||||
return new VoteState()
|
||||
return Map(new VoteState())
|
||||
|
||||
default:
|
||||
return state
|
||||
|
||||
@@ -11,6 +11,7 @@ import { eventChannel, Channel } from 'redux-saga'
|
||||
import { ServerRequestStatusType } from 'store/actions/serverRequestStatusType'
|
||||
import { Post } from 'core/domain/posts'
|
||||
import { postSelector } from 'store/reducers/posts/postSelector'
|
||||
import {Map} from 'immutable'
|
||||
/**
|
||||
* Get service providers
|
||||
*/
|
||||
@@ -40,15 +41,15 @@ function* setComments(ownerId: string, postId: string, comments: postComments) {
|
||||
*/
|
||||
yield put(commentActions.addCommentList(comments))
|
||||
let commentsCount: number
|
||||
const post: Post = yield select(postSelector.getPost, ownerId, postId)
|
||||
const post: Map<string, any> = yield select(postSelector.getPost, ownerId, postId)
|
||||
if (post) {
|
||||
const desiredComments = comments[postId]
|
||||
if (desiredComments) {
|
||||
commentsCount = Object.keys(desiredComments).length
|
||||
let sortedObjects = yield CommentAPI.sortCommentsByDate(desiredComments)
|
||||
post.comments = sortedObjects
|
||||
post.commentCounter = commentsCount
|
||||
yield put(postActions.updatePost(post))
|
||||
const updatedPost = post.set('comments', Map(sortedObjects))
|
||||
.set('commentCounter', commentsCount)
|
||||
yield put(postActions.updatePost(updatedPost))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,10 +73,8 @@ function* dbFetchComments(ownerId: string, postId: string) {
|
||||
yield call(setComments, ownerId, postId, comments)
|
||||
}
|
||||
} finally {
|
||||
console.trace('FiNALLY')
|
||||
if (yield cancelled()) {
|
||||
channelSubscription.close()
|
||||
console.trace('comments cancelled')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
src/typings/react-loadable.d.ts
vendored
Normal file
1
src/typings/react-loadable.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module 'react-loadable'
|
||||
63
yarn.lock
63
yarn.lock
@@ -141,6 +141,12 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-helmet@^5.0.5":
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-5.0.5.tgz#30a12b0431732a20882f0fa9b75bf56ff91700d3"
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-infinite-scroller@^1.0.4":
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-infinite-scroller/-/react-infinite-scroller-1.0.6.tgz#ab36d95ce25712b70ccff439f2a3204bb15476d9"
|
||||
@@ -211,6 +217,13 @@
|
||||
"@types/react" "*"
|
||||
redux "^3.6.0"
|
||||
|
||||
"@types/redux-immutable@^3.0.38":
|
||||
version "3.0.38"
|
||||
resolved "https://registry.yarnpkg.com/@types/redux-immutable/-/redux-immutable-3.0.38.tgz#9e2fcce4a9c64e60f13de2165d2765f7af85d487"
|
||||
dependencies:
|
||||
immutable "^3.8.1"
|
||||
redux "^3.6.0"
|
||||
|
||||
"@types/redux-logger@^3.0.4":
|
||||
version "3.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/redux-logger/-/redux-logger-3.0.5.tgz#d1a02758f90845899cd304aa0912daeba2028eb6"
|
||||
@@ -2250,6 +2263,10 @@ execa@^0.7.0:
|
||||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
exenv@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||
|
||||
expand-brackets@^0.1.4:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
|
||||
@@ -3175,6 +3192,10 @@ ignore-walk@^3.0.1:
|
||||
dependencies:
|
||||
minimatch "^3.0.4"
|
||||
|
||||
immutable@^3.8.1, immutable@^3.8.2:
|
||||
version "3.8.2"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
|
||||
|
||||
import-lazy@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
|
||||
@@ -5846,7 +5867,7 @@ promzard@^0.3.0:
|
||||
dependencies:
|
||||
read "1"
|
||||
|
||||
prop-types@^15.0.0, prop-types@^15.5.7:
|
||||
prop-types@^15.0.0, prop-types@^15.5.0, prop-types@^15.5.7:
|
||||
version "15.6.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
|
||||
dependencies:
|
||||
@@ -6133,6 +6154,15 @@ react-event-listener@^0.5.1:
|
||||
prop-types "^15.6.0"
|
||||
warning "^3.0.0"
|
||||
|
||||
react-helmet@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.0.tgz#a81811df21313a6d55c5f058c4aeba5d6f3d97a7"
|
||||
dependencies:
|
||||
deep-equal "^1.0.1"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.5.4"
|
||||
react-side-effect "^1.1.0"
|
||||
|
||||
react-infinite-scroller@^1.1.2:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-infinite-scroller/-/react-infinite-scroller-1.1.3.tgz#c4230024bc237ce876c76b2e38d77dc1f6aabb26"
|
||||
@@ -6169,9 +6199,15 @@ react-linkify@^0.2.1:
|
||||
prop-types "^15.5.8"
|
||||
tlds "^1.57.0"
|
||||
|
||||
react-localize-redux@^2.15.1:
|
||||
version "2.15.1"
|
||||
resolved "https://registry.yarnpkg.com/react-localize-redux/-/react-localize-redux-2.15.1.tgz#b32969eae191bcbcca2f0ffdc20802768fec0601"
|
||||
react-loadable@^5.3.1:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-loadable/-/react-loadable-5.3.1.tgz#9699e9a08fed49bacd69caaa282034b62a76bcdd"
|
||||
dependencies:
|
||||
prop-types "^15.5.0"
|
||||
|
||||
react-localize-redux@^2.16.0:
|
||||
version "2.16.0"
|
||||
resolved "https://registry.yarnpkg.com/react-localize-redux/-/react-localize-redux-2.16.0.tgz#9e4b1c4703984decfb33fcf8f9ab51454af5211e"
|
||||
dependencies:
|
||||
flat "^2.0.1"
|
||||
reselect "^3.0.1"
|
||||
@@ -6290,6 +6326,13 @@ react-share@^2.0.0:
|
||||
jsonp "^0.2.1"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-side-effect@^1.1.0:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.1.5.tgz#f26059e50ed9c626d91d661b9f3c8bb38cd0ff2d"
|
||||
dependencies:
|
||||
exenv "^1.2.1"
|
||||
shallowequal "^1.0.1"
|
||||
|
||||
react-string-replace@^0.4.0:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-string-replace/-/react-string-replace-0.4.1.tgz#024c6ac0a91163ecae439a1b197d3e1660c98c0d"
|
||||
@@ -6513,6 +6556,10 @@ redux-devtools-dock-monitor@^1.1.3:
|
||||
react-dock "^0.2.4"
|
||||
react-pure-render "^1.0.2"
|
||||
|
||||
redux-devtools-extension@^2.13.2:
|
||||
version "2.13.2"
|
||||
resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.2.tgz#e0f9a8e8dfca7c17be92c7124958a3b94eb2911d"
|
||||
|
||||
redux-devtools-instrument@^1.0.1:
|
||||
version "1.8.3"
|
||||
resolved "https://registry.yarnpkg.com/redux-devtools-instrument/-/redux-devtools-instrument-1.8.3.tgz#c510d67ab4e5e4525acd6e410c25ab46b85aca7c"
|
||||
@@ -6544,6 +6591,10 @@ redux-devtools@^3.4.1:
|
||||
prop-types "^15.5.7"
|
||||
redux-devtools-instrument "^1.0.1"
|
||||
|
||||
redux-immutable@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-immutable/-/redux-immutable-4.0.0.tgz#3a1a32df66366462b63691f0e1dc35e472bbc9f3"
|
||||
|
||||
redux-logger@^3.0.1:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-3.0.6.tgz#f7555966f3098f3c88604c449cf0baf5778274bf"
|
||||
@@ -7006,6 +7057,10 @@ sha@~2.0.1:
|
||||
graceful-fs "^4.1.2"
|
||||
readable-stream "^2.0.2"
|
||||
|
||||
shallowequal@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.0.2.tgz#1561dbdefb8c01408100319085764da3fcf83f8f"
|
||||
|
||||
shebang-command@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
||||
|
||||
Reference in New Issue
Block a user