[Update Package] Update material UI package which changed the UI code too.
This commit is contained in:
@@ -32,7 +32,8 @@
|
|||||||
"inversify": "^4.6.0",
|
"inversify": "^4.6.0",
|
||||||
"keycode": "^2.1.9",
|
"keycode": "^2.1.9",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"material-ui": "^0.19.4",
|
"material-ui": "^1.0.0-beta.31",
|
||||||
|
"material-ui-icons": "^1.0.0-beta.17",
|
||||||
"moment": "^2.18.1",
|
"moment": "^2.18.1",
|
||||||
"morgan": "^1.8.1",
|
"morgan": "^1.8.1",
|
||||||
"node-env-file": "^0.1.8",
|
"node-env-file": "^0.1.8",
|
||||||
@@ -62,16 +63,17 @@
|
|||||||
"save": "^2.3.0",
|
"save": "^2.3.0",
|
||||||
"script-loader": "^0.7.0",
|
"script-loader": "^0.7.0",
|
||||||
"style-loader": "^0.16.1",
|
"style-loader": "^0.16.1",
|
||||||
|
"typeface-roboto": "0.0.50",
|
||||||
"url-loader": "^0.5.8",
|
"url-loader": "^0.5.8",
|
||||||
"uuid": "^3.0.1"
|
"uuid": "^3.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/classnames": "^2.2.3",
|
||||||
"@types/lodash": "^4.14.77",
|
"@types/lodash": "^4.14.77",
|
||||||
"@types/material-ui": "^0.18.2",
|
|
||||||
"@types/moment": "^2.13.0",
|
"@types/moment": "^2.13.0",
|
||||||
"@types/node": "^8.0.33",
|
"@types/node": "^8.0.33",
|
||||||
"@types/prop-types": "^15.5.2",
|
"@types/prop-types": "^15.5.2",
|
||||||
"@types/react": "^16.0.10",
|
"@types/react": "^16.0.35",
|
||||||
"@types/react-dom": "^16.0.1",
|
"@types/react-dom": "^16.0.1",
|
||||||
"@types/react-event-listener": "^0.4.4",
|
"@types/react-event-listener": "^0.4.4",
|
||||||
"@types/react-redux": "^5.0.10",
|
"@types/react-redux": "^5.0.10",
|
||||||
|
|||||||
@@ -217,14 +217,11 @@ export const dbUpdateCircle = (newCircle: Circle) => {
|
|||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
|
|
||||||
// Write the new data simultaneously in the list
|
// Write the new data simultaneously in the list
|
||||||
let circle: Circle = getState().circle.userTies[uid][newCircle.id!]
|
let circle: Circle = {...getState().circle.circleList[newCircle.id!]}
|
||||||
let updatedCircle: Circle = {
|
circle.name = newCircle.name
|
||||||
name: newCircle.name || circle.name,
|
|
||||||
isSystem : false
|
|
||||||
}
|
|
||||||
return circleService.updateCircle(uid, newCircle.id!, circle)
|
return circleService.updateCircle(uid, newCircle.id!, circle)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(updateCircle({ id: newCircle.id, ...updatedCircle }))
|
dispatch(updateCircle({ id: newCircle.id, ...circle }))
|
||||||
}, (error: SocialError) => {
|
}, (error: SocialError) => {
|
||||||
dispatch(globalActions.showErrorMessage(error.message))
|
dispatch(globalActions.showErrorMessage(error.message))
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,10 +14,15 @@ import { CommentActionType } from 'constants/commentActionType'
|
|||||||
import * as globalActions from 'actions/globalActions'
|
import * as globalActions from 'actions/globalActions'
|
||||||
import * as notifyActions from 'actions/notifyActions'
|
import * as notifyActions from 'actions/notifyActions'
|
||||||
import * as postActions from 'actions/postActions'
|
import * as postActions from 'actions/postActions'
|
||||||
|
import * as serverActions from 'actions/serverActions'
|
||||||
|
|
||||||
import { ICommentService } from 'core/services/comments'
|
import { ICommentService } from 'core/services/comments'
|
||||||
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
import { SocialProviderTypes } from 'core/socialProviderTypes'
|
||||||
import { provider } from '../socialEngine'
|
import { provider } from '../socialEngine'
|
||||||
|
import StringAPI from 'api/StringAPI'
|
||||||
|
import { ServerRequestType } from 'constants/serverRequestType'
|
||||||
|
import { ServerRequestModel } from 'models/server'
|
||||||
|
import { ServerRequestStatusType } from 'actions/serverRequestStatusType'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get service providers
|
* Get service providers
|
||||||
@@ -82,9 +87,16 @@ export const dbGetComments = (ownerUserId: string, postId: string) => {
|
|||||||
const state = getState()
|
const state = getState()
|
||||||
let uid: string = getState().authorize.uid
|
let uid: string = getState().authorize.uid
|
||||||
if (uid) {
|
if (uid) {
|
||||||
|
// Set server request status to {Sent}
|
||||||
|
const getCommentsRequest = createGetCommentsRequest(postId)
|
||||||
|
dispatch(serverActions.sendRequest(getCommentsRequest))
|
||||||
|
|
||||||
return commentService.getComments(postId, (comments: {[postId: string]: {[commentId: string]: Comment}}) => {
|
return commentService.getComments(postId, (comments: {[postId: string]: {[commentId: string]: Comment}}) => {
|
||||||
|
|
||||||
|
// Set server request status to {OK}
|
||||||
|
getCommentsRequest.status = ServerRequestStatusType.OK
|
||||||
|
dispatch(serverActions.sendRequest(getCommentsRequest))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Workout getting the number of post's comment and getting three last comments
|
* Workout getting the number of post's comment and getting three last comments
|
||||||
*/
|
*/
|
||||||
@@ -174,6 +186,19 @@ export const dbDeleteComment = (id?: string | null, postId?: string) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create get comments server request model
|
||||||
|
*/
|
||||||
|
const createGetCommentsRequest = (postId: string) => {
|
||||||
|
const requestId = StringAPI.createServerRequestId(ServerRequestType.CommentGetComments, postId)
|
||||||
|
return new ServerRequestModel(
|
||||||
|
ServerRequestType.CommentGetComments,
|
||||||
|
requestId,
|
||||||
|
'',
|
||||||
|
ServerRequestStatusType.Sent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/* _____________ CRUD State _____________ */
|
/* _____________ CRUD State _____________ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,21 +3,38 @@ import React, { Component } from 'react'
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import { grey400, darkBlack, lightBlack } from 'material-ui/styles/colors'
|
import { grey } from 'material-ui/colors'
|
||||||
import { List, ListItem } from 'material-ui/List'
|
import List, {
|
||||||
import SvgGroup from 'material-ui/svg-icons/action/group-work'
|
ListItem,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemSecondaryAction,
|
||||||
|
ListItemText,
|
||||||
|
ListSubheader
|
||||||
|
} from 'material-ui/List'
|
||||||
|
import SvgGroup from 'material-ui-icons/groupWork'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'
|
import MoreVertIcon from 'material-ui-icons/moreVert'
|
||||||
import IconMenu from 'material-ui/IconMenu'
|
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import MenuItem from 'material-ui/MenuItem'
|
import { MenuList, MenuItem } from 'material-ui/Menu'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
import { Manager, Target, Popper } from 'react-popper'
|
||||||
|
import Grow from 'material-ui/transitions/Grow'
|
||||||
|
import ClickAwayListener from 'material-ui/utils/ClickAwayListener'
|
||||||
|
import classNames from 'classnames'
|
||||||
import IconButtonElement from 'layouts/IconButtonElement'
|
import IconButtonElement from 'layouts/IconButtonElement'
|
||||||
import Dialog from 'material-ui/Dialog'
|
import Dialog, {
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
|
DialogTitle
|
||||||
|
} from 'material-ui/Dialog'
|
||||||
import Divider from 'material-ui/Divider'
|
import Divider from 'material-ui/Divider'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
import SvgClose from 'material-ui/svg-icons/navigation/close'
|
import SvgClose from 'material-ui-icons/close'
|
||||||
import AppBar from 'material-ui/AppBar'
|
import AppBar from 'material-ui/AppBar'
|
||||||
|
import Paper from 'material-ui/Paper'
|
||||||
|
import Collapse from 'material-ui/transitions/Collapse'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import UserAvatar from 'components/userAvatar'
|
import UserAvatar from 'components/userAvatar'
|
||||||
@@ -32,6 +49,24 @@ import { ICircleComponentState } from './ICircleComponentState'
|
|||||||
import { Circle, UserTie } from 'core/domain/circles'
|
import { Circle, UserTie } from 'core/domain/circles'
|
||||||
import { Profile } from 'core/domain/users/profile'
|
import { Profile } from 'core/domain/users/profile'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
root: {
|
||||||
|
width: '100%',
|
||||||
|
paddingRight: '0px',
|
||||||
|
backgroundColor: theme.palette.background.paper
|
||||||
|
},
|
||||||
|
popperOpen: {
|
||||||
|
zIndex: 10
|
||||||
|
},
|
||||||
|
popperClose: {
|
||||||
|
pointerEvents: 'none',
|
||||||
|
zIndex: 0
|
||||||
|
},
|
||||||
|
dialogPaper: {
|
||||||
|
minWidth: 400
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*/
|
*/
|
||||||
@@ -52,6 +87,14 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
|
|||||||
},
|
},
|
||||||
settingContent: {
|
settingContent: {
|
||||||
maxWidth: '400px'
|
maxWidth: '400px'
|
||||||
|
},
|
||||||
|
listMenu: {
|
||||||
|
color: 'rgba(0,0,0,0.87)',
|
||||||
|
fontSize: '16px',
|
||||||
|
marginRight: '8px',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
overflow: 'hidden'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +102,7 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
|
|||||||
* Component constructor
|
* Component constructor
|
||||||
* @param {object} props is an object properties of component
|
* @param {object} props is an object properties of component
|
||||||
*/
|
*/
|
||||||
constructor (props: ICircleComponentProps) {
|
constructor(props: ICircleComponentProps) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
// Defaul state
|
// Defaul state
|
||||||
@@ -75,7 +118,12 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
|
|||||||
/**
|
/**
|
||||||
* Save operation will be disable if user doesn't meet requirement
|
* Save operation will be disable if user doesn't meet requirement
|
||||||
*/
|
*/
|
||||||
disabledSave: false
|
disabledSave: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether meu is open
|
||||||
|
*/
|
||||||
|
isMenuOpen: false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binding functions to `this`
|
// Binding functions to `this`
|
||||||
@@ -99,6 +147,24 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle close menu
|
||||||
|
*/
|
||||||
|
handleCloseMenu = () => {
|
||||||
|
this.setState({
|
||||||
|
isMenuOpen: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle open menu
|
||||||
|
*/
|
||||||
|
handleOpenMenu = () => {
|
||||||
|
this.setState({
|
||||||
|
isMenuOpen: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update user's circle
|
* Update user's circle
|
||||||
*
|
*
|
||||||
@@ -139,49 +205,74 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
|
|||||||
let usersParsed: any = []
|
let usersParsed: any = []
|
||||||
|
|
||||||
if (usersOfCircle) {
|
if (usersOfCircle) {
|
||||||
console.trace('usersOfCircle',usersOfCircle)
|
|
||||||
Object.keys(usersOfCircle).forEach((userId, index) => {
|
Object.keys(usersOfCircle).forEach((userId, index) => {
|
||||||
const { fullName } = usersOfCircle[userId]
|
const { fullName } = usersOfCircle[userId]
|
||||||
let avatar = usersOfCircle && usersOfCircle[userId] ? usersOfCircle[userId].avatar || '' : ''
|
let avatar = usersOfCircle && usersOfCircle[userId] ? usersOfCircle[userId].avatar || '' : ''
|
||||||
usersParsed.push(<ListItem
|
usersParsed.push(
|
||||||
key={`${this.props.id}.${userId}`}
|
<ListItem
|
||||||
style={this.styles.userListItem as any}
|
button
|
||||||
value={2}
|
key={`${this.props.id}.${userId}`}
|
||||||
primaryText={fullName}
|
style={this.styles.userListItem as any}
|
||||||
leftAvatar={<UserAvatar fullName={fullName!} fileName={avatar} />}
|
value={2}
|
||||||
onClick={() => this.props.goTo!(`/${userId}`)}
|
onClick={() => this.props.goTo!(`/${userId}`)}
|
||||||
/>)
|
>
|
||||||
|
<UserAvatar fullName={fullName!} fileName={avatar} />
|
||||||
|
<ListItemText inset primary={fullName} />
|
||||||
|
</ListItem>)
|
||||||
|
|
||||||
})
|
})
|
||||||
return usersParsed
|
return usersParsed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Right icon menue of circle
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @memberof CircleComponent
|
|
||||||
*/
|
|
||||||
// tslint:disable-next-line:member-ordering
|
|
||||||
rightIconMenu: any = (
|
|
||||||
<IconMenu iconButtonElement={IconButtonElement} style={this.styles.rightIconMenu as any}>
|
|
||||||
<MenuItem primaryText='Delete circle' onClick={this.handleDeleteCircle} />
|
|
||||||
<MenuItem primaryText='Circle settings' onClick={this.props.openCircleSettings} />
|
|
||||||
</IconMenu>
|
|
||||||
)
|
|
||||||
/**
|
/**
|
||||||
* Reneder component DOM
|
* Reneder component DOM
|
||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render() {
|
||||||
|
|
||||||
|
const { circle, classes } = this.props
|
||||||
|
const { isMenuOpen } = this.state
|
||||||
|
/**
|
||||||
|
* Right icon menue of circle
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// tslint:disable-next-line:member-ordering
|
||||||
|
const rightIconMenu = (
|
||||||
|
<Manager>
|
||||||
|
<Target>
|
||||||
|
<IconButton
|
||||||
|
aria-owns={isMenuOpen! ? 'circle-menu' : null}
|
||||||
|
aria-haspopup='true'
|
||||||
|
onClick={this.handleOpenMenu}
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Target>
|
||||||
|
<Popper
|
||||||
|
placement='bottom-start'
|
||||||
|
eventsEnabled={isMenuOpen}
|
||||||
|
className={classNames({ [classes.popperClose]: !isMenuOpen }, { [classes.popperOpen]: isMenuOpen })}
|
||||||
|
>
|
||||||
|
<ClickAwayListener onClickAway={this.handleCloseMenu}>
|
||||||
|
<Grow in={isMenuOpen} id='circle-menu' style={{ transformOrigin: '0 0 0' }}>
|
||||||
|
<Paper>
|
||||||
|
<MenuList role='menu'>
|
||||||
|
<MenuItem onClick={this.handleDeleteCircle} > Delete circle </MenuItem>
|
||||||
|
<MenuItem onClick={this.props.openCircleSettings}> Circle settings </MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Popper>
|
||||||
|
</Manager>
|
||||||
|
)
|
||||||
|
|
||||||
const {circle} = this.props
|
|
||||||
const circleTitle = (
|
const circleTitle = (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between' }}>
|
<div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||||
<div style={{ paddingRight: '10px' }}>
|
<div style={{ paddingRight: '10px' }}>
|
||||||
<SvgClose onClick={this.props.closeCircleSettings} hoverColor={grey400} style={{ cursor: 'pointer' }} />
|
<SvgClose onClick={this.props.closeCircleSettings} style={{ cursor: 'pointer' }} />
|
||||||
</div>
|
</div>
|
||||||
<div style={{
|
<div style={{
|
||||||
color: 'rgba(0,0,0,0.87)',
|
color: 'rgba(0,0,0,0.87)',
|
||||||
@@ -191,45 +282,53 @@ export class CircleComponent extends Component<ICircleComponentProps, ICircleCom
|
|||||||
Circle settings
|
Circle settings
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginTop: '-9px' }}>
|
<div style={{ marginTop: '-9px' }}>
|
||||||
<FlatButton label='SAVE' primary={true} disabled={this.state.disabledSave} onClick={this.handleUpdateCircle} />
|
<Button color='primary' disabled={this.state.disabledSave} onClick={this.handleUpdateCircle} > SAVE </Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ListItem
|
<ListItem
|
||||||
key={this.props.id}
|
className={classes.root}
|
||||||
style={{ backgroundColor: '#fff', borderBottom: '1px solid rgba(0,0,0,0.12)', height: '72px', padding: '12px 0' }}
|
key={this.props.id + '-CircleComponent'}
|
||||||
primaryText={<span style={{ color: 'rgba(0,0,0,0.87)', fontSize: '16px', marginRight: '8px', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }}>{this.props.circle.name}</span>}
|
|
||||||
leftIcon={<SvgGroup style={{ width: '40px', height: '40px', transform: 'translate(0px, -9px)', fill: '#bdbdbd' }} />}
|
|
||||||
rightIconButton={!circle.isSystem ? this.rightIconMenu : null}
|
|
||||||
initiallyOpen={false}
|
|
||||||
onClick={this.handleToggleCircle}
|
onClick={this.handleToggleCircle}
|
||||||
open={this.state.open}
|
|
||||||
nestedItems={this.userList()}
|
|
||||||
>
|
>
|
||||||
<Dialog
|
<ListItemIcon className={classes.icon}>
|
||||||
key={this.props.id}
|
<SvgGroup />
|
||||||
title={circleTitle}
|
</ListItemIcon>
|
||||||
modal={false}
|
<ListItemText inset primary={<span style={this.styles}>{this.props.circle.name}</span>} />
|
||||||
open={this.props.openSetting!}
|
<ListItemSecondaryAction>
|
||||||
onRequestClose={this.props.closeCircleSettings}
|
{ circle.isSystem ? null : rightIconMenu }
|
||||||
overlayStyle={this.styles.settingOverlay as any}
|
</ListItemSecondaryAction>
|
||||||
contentStyle={this.styles.settingContent as any}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
hintText='Circle name'
|
|
||||||
floatingLabelText='Circle name'
|
|
||||||
onChange={this.handleChangeCircleName}
|
|
||||||
value={this.state.circleName}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</div>
|
<Collapse component='li' in={this.state.open} timeout='auto' unmountOnExit>
|
||||||
|
<List disablePadding>
|
||||||
|
{this.userList()}
|
||||||
|
</List>
|
||||||
|
</Collapse>
|
||||||
|
<Dialog
|
||||||
|
key={this.props.id}
|
||||||
|
open={this.props.openSetting!}
|
||||||
|
onClose={this.props.closeCircleSettings}
|
||||||
|
classes={{
|
||||||
|
paper: classes.dialogPaper
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle >{circleTitle}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
autoFocus
|
||||||
|
placeholder='Circle name'
|
||||||
|
label='Circle name'
|
||||||
|
onChange={this.handleChangeCircleName}
|
||||||
|
value={this.state.circleName}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,13 +358,13 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICircleComponentProps) => {
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any, ownProps: ICircleComponentProps) => {
|
const mapStateToProps = (state: any, ownProps: ICircleComponentProps) => {
|
||||||
const {circle, authorize, server} = state
|
const { circle, authorize, server } = state
|
||||||
const {userTies} = circle
|
const { userTies } = circle
|
||||||
const { uid } = state.authorize
|
const { uid } = state.authorize
|
||||||
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
const circles: { [circleId: string]: Circle } = circle ? (circle.circleList || {}) : {}
|
||||||
const currentCircle = (circles ? circles[ownProps.id] : {}) as Circle
|
const currentCircle = (circles ? circles[ownProps.id] : {}) as Circle
|
||||||
|
const circleId = ownProps.circle.id!
|
||||||
let usersOfCircle: {[userId: string]: UserTie} = {}
|
let usersOfCircle: { [userId: string]: UserTie } = {}
|
||||||
Object.keys(userTies).forEach((userTieId) => {
|
Object.keys(userTies).forEach((userTieId) => {
|
||||||
const theUserTie = userTies[userTieId] as UserTie
|
const theUserTie = userTies[userTieId] as UserTie
|
||||||
if (theUserTie.circleIdList!.indexOf(ownProps.id) > -1) {
|
if (theUserTie.circleIdList!.indexOf(ownProps.id) > -1) {
|
||||||
@@ -277,11 +376,11 @@ const mapStateToProps = (state: any, ownProps: ICircleComponentProps) => {
|
|||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
usersOfCircle,
|
usersOfCircle,
|
||||||
openSetting: state.circle ? (currentCircle ? (currentCircle.openCircleSettings || false) : false) : false,
|
openSetting: (state.circle && state.circle.openSetting && state.circle.openSetting[circleId]) ? state.circle.openSetting[circleId] : false,
|
||||||
userInfo: state.user.info
|
userInfo: state.user.info
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(CircleComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(CircleComponent as any) as any)
|
||||||
|
|||||||
@@ -78,4 +78,9 @@ export interface ICircleComponentProps {
|
|||||||
* @memberof ICircleComponentProps
|
* @memberof ICircleComponentProps
|
||||||
*/
|
*/
|
||||||
openCircleSettings?: () => any
|
openCircleSettings?: () => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,4 +24,9 @@ export interface ICircleComponentState {
|
|||||||
* @memberof ICircleComponentState
|
* @memberof ICircleComponentState
|
||||||
*/
|
*/
|
||||||
disabledSave: boolean
|
disabledSave: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether circle menu is open
|
||||||
|
*/
|
||||||
|
isMenuOpen: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,19 +9,24 @@ import Linkify from 'react-linkify'
|
|||||||
import { Comment } from 'core/domain/comments'
|
import { Comment } from 'core/domain/comments'
|
||||||
|
|
||||||
// - Import material UI libraries
|
// - Import material UI libraries
|
||||||
import { List, ListItem } from 'material-ui/List'
|
|
||||||
import Divider from 'material-ui/Divider'
|
import Divider from 'material-ui/Divider'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import { grey400, darkBlack, lightBlack } from 'material-ui/styles/colors'
|
import { grey } from 'material-ui/colors'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'
|
import MoreVertIcon from 'material-ui-icons/moreVert'
|
||||||
import IconMenu from 'material-ui/IconMenu'
|
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List'
|
||||||
import MenuItem from 'material-ui/MenuItem'
|
import Menu, { MenuList, MenuItem } from 'material-ui/Menu'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
import { Manager, Target, Popper } from 'react-popper'
|
||||||
|
import { Card, CardActions, CardHeader, CardMedia, CardContent } from 'material-ui'
|
||||||
|
import Grow from 'material-ui/transitions/Grow'
|
||||||
|
import ClickAwayListener from 'material-ui/utils/ClickAwayListener'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import UserAvatarComponent from 'components/userAvatar'
|
import UserAvatar from 'components/userAvatar'
|
||||||
|
|
||||||
// - Import API
|
// - Import API
|
||||||
|
|
||||||
@@ -35,10 +40,58 @@ import * as userActions from 'actions/userActions'
|
|||||||
import { ICommentComponentProps } from './ICommentComponentProps'
|
import { ICommentComponentProps } from './ICommentComponentProps'
|
||||||
import { ICommentComponentState } from './ICommentComponentState'
|
import { ICommentComponentState } from './ICommentComponentState'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
textField: {
|
||||||
|
fontWeight: 100,
|
||||||
|
fontSize: '14px'
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
padding: '2px 3px 3px 10px'
|
||||||
|
},
|
||||||
|
popperOpen: {
|
||||||
|
zIndex: 11
|
||||||
|
},
|
||||||
|
popperClose: {
|
||||||
|
pointerEvents: 'none',
|
||||||
|
zIndex: 0
|
||||||
|
},
|
||||||
|
iconButton: {
|
||||||
|
top: 0,
|
||||||
|
display: 'flex',
|
||||||
|
right: 4,
|
||||||
|
flexDirection: 'row-reverse',
|
||||||
|
position: 'absolute'
|
||||||
|
|
||||||
|
},
|
||||||
|
commentBody: {
|
||||||
|
color: 'black',
|
||||||
|
fontWeight: 100,
|
||||||
|
fontSize: '12px',
|
||||||
|
height: '100%',
|
||||||
|
border: 'none',
|
||||||
|
width: '100%',
|
||||||
|
outline: 'none',
|
||||||
|
resize: 'none'
|
||||||
|
},
|
||||||
|
rightIconMenuItem: {
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 300,
|
||||||
|
paddingLeft: 6,
|
||||||
|
paddingRight: 6,
|
||||||
|
paddingTop: 0,
|
||||||
|
paddingBottom: 0
|
||||||
|
|
||||||
|
},
|
||||||
|
moreIcon: {
|
||||||
|
width: '0.6em',
|
||||||
|
height: '0.6em'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*/
|
*/
|
||||||
export class CommentComponent extends Component<ICommentComponentProps,ICommentComponentState> {
|
export class CommentComponent extends Component<ICommentComponentProps, ICommentComponentState> {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
/**
|
/**
|
||||||
@@ -62,16 +115,8 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
* @memberof CommentComponent
|
* @memberof CommentComponent
|
||||||
*/
|
*/
|
||||||
styles = {
|
styles = {
|
||||||
comment: {
|
|
||||||
marginBottom: '12px'
|
|
||||||
},
|
|
||||||
iconButton: {
|
|
||||||
width: 16,
|
|
||||||
height: 16
|
|
||||||
|
|
||||||
},
|
|
||||||
author: {
|
author: {
|
||||||
fontSize: '13px',
|
fontSize: '10px',
|
||||||
paddingRight: '10px',
|
paddingRight: '10px',
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
color: 'rgba(0,0,0,0.87)',
|
color: 'rgba(0,0,0,0.87)',
|
||||||
@@ -79,18 +124,6 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
overflow: 'hidden'
|
overflow: 'hidden'
|
||||||
|
|
||||||
},
|
},
|
||||||
commentBody: {
|
|
||||||
fontSize: '13px',
|
|
||||||
lineHeight: '20px',
|
|
||||||
color: 'rgba(0,0,0,0.87)',
|
|
||||||
fontWeight: 300,
|
|
||||||
height: '',
|
|
||||||
display: 'block'
|
|
||||||
|
|
||||||
},
|
|
||||||
rightIconMenuItem: {
|
|
||||||
fontSize: '14px'
|
|
||||||
},
|
|
||||||
textarea: {
|
textarea: {
|
||||||
fontWeight: 100,
|
fontWeight: 100,
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
@@ -146,7 +179,11 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
/**
|
/**
|
||||||
* If it's true the post owner is the logged in user which this post be long to the comment
|
* If it's true the post owner is the logged in user which this post be long to the comment
|
||||||
*/
|
*/
|
||||||
isPostOwner: false
|
isPostOwner: false,
|
||||||
|
/**
|
||||||
|
* The anchor of comment menu element
|
||||||
|
*/
|
||||||
|
openMenu: false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,8 +201,8 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
* @param {event} evt is an event passed by clicking on edit button
|
* @param {event} evt is an event passed by clicking on edit button
|
||||||
*/
|
*/
|
||||||
handleEditComment = (evt: any) => {
|
handleEditComment = (evt: any) => {
|
||||||
this.inputText.style.height = this.divComment.clientHeight + 'px'
|
this.setState({openMenu: false})
|
||||||
this.props.openEditor()
|
this.props.openEditor!()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,7 +214,7 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
this.setState({
|
this.setState({
|
||||||
text: this.state.initialText
|
text: this.state.initialText
|
||||||
})
|
})
|
||||||
this.props.closeEditor()
|
this.props.closeEditor!()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,10 +222,10 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
* @param {event} evt is an event passed by clicking on post button
|
* @param {event} evt is an event passed by clicking on post button
|
||||||
*/
|
*/
|
||||||
handleUpdateComment = (evt: any) => {
|
handleUpdateComment = (evt: any) => {
|
||||||
const {comment} = this.props
|
const { comment } = this.props
|
||||||
comment.editorStatus = undefined
|
comment.editorStatus = undefined
|
||||||
comment.text = this.state.text
|
comment.text = this.state.text
|
||||||
this.props.update(comment)
|
this.props.update!(comment)
|
||||||
this.setState({
|
this.setState({
|
||||||
initialText: this.state.text
|
initialText: this.state.text
|
||||||
})
|
})
|
||||||
@@ -202,7 +239,6 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
*/
|
*/
|
||||||
handleOnChange = (evt: any) => {
|
handleOnChange = (evt: any) => {
|
||||||
const data = evt.target.value
|
const data = evt.target.value
|
||||||
this.inputText.style.height = evt.target.scrollHeight + 'px'
|
|
||||||
if (data.length === 0 || data.trim() === '' || data.trim() === this.state.initialText) {
|
if (data.length === 0 || data.trim() === '' || data.trim() === this.state.initialText) {
|
||||||
this.setState({
|
this.setState({
|
||||||
text: data,
|
text: data,
|
||||||
@@ -223,14 +259,28 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
* @param {string} id comment identifire
|
* @param {string} id comment identifire
|
||||||
* @param {string} postId post identifier which comment belong to
|
* @param {string} postId post identifier which comment belong to
|
||||||
*/
|
*/
|
||||||
handleDelete = (evt: any, id?: string| null, postId?: string) => {
|
handleDelete = (evt: any, id?: string | null, postId?: string) => {
|
||||||
this.props.delete(id, postId)
|
this.props.delete!(id, postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle comment menu
|
||||||
|
*/
|
||||||
|
handleCommentMenu = (event: any) => {
|
||||||
|
this.setState({ openMenu: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle close request for comment menu
|
||||||
|
*/
|
||||||
|
handleCloseCommentMenu = () => {
|
||||||
|
this.setState({ openMenu: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount () {
|
componentWillMount () {
|
||||||
const {userId} = this.props.comment
|
const { userId } = this.props.comment
|
||||||
if (!this.props.isCommentOwner && !this.props.info[userId!]) {
|
if (!this.props.isCommentOwner && !this.props.info![userId!]) {
|
||||||
this.props.getUserInfo()
|
this.props.getUserInfo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,56 +293,94 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
/**
|
/**
|
||||||
* Comment object from props
|
* Comment object from props
|
||||||
*/
|
*/
|
||||||
const {comment} = this.props
|
const { comment, classes, fullName, avatar } = this.props
|
||||||
|
|
||||||
const iconButtonElement = (
|
const { openMenu } = this.state
|
||||||
<IconButton style={this.styles.iconButton} iconStyle={this.styles.iconButton}
|
|
||||||
touch={true}
|
|
||||||
>
|
|
||||||
<MoreVertIcon color={grey400} viewBox='9 0 24 24' />
|
|
||||||
</IconButton>
|
|
||||||
)
|
|
||||||
|
|
||||||
const RightIconMenu = () => (
|
const RightIconMenu = () => (
|
||||||
<IconMenu iconButtonElement={iconButtonElement} style={{ display: 'block', position: 'absolute', top: '0px', right: '4px' }}>
|
<Manager
|
||||||
<MenuItem style={{ fontSize: '14px' }}>Reply</MenuItem>
|
className={classes.iconButton}
|
||||||
{this.props.isCommentOwner ? (<MenuItem style={this.styles.rightIconMenuItem} onClick={this.handleEditComment}>Edit</MenuItem>) : ''}
|
>
|
||||||
{(this.props.isCommentOwner || this.props.isPostOwner) ? ( <MenuItem style={{ fontSize: '14px' }} onClick={(evt) => this.handleDelete(evt, comment.id, comment.postId)}>Delete</MenuItem>) : ''}
|
<Target>
|
||||||
</IconMenu>
|
<IconButton
|
||||||
|
aria-owns={openMenu! ? 'comment-menu' : null}
|
||||||
|
aria-haspopup='true'
|
||||||
|
onClick={this.handleCommentMenu}
|
||||||
|
>
|
||||||
|
<MoreVertIcon className={classes.moreIcon} />
|
||||||
|
</IconButton>
|
||||||
|
</Target>
|
||||||
|
<Popper
|
||||||
|
placement='bottom-start'
|
||||||
|
eventsEnabled={openMenu!}
|
||||||
|
className={classNames({ [classes.popperClose]: !openMenu! }, { [classes.popperOpen]: openMenu! })}
|
||||||
|
>
|
||||||
|
<ClickAwayListener onClickAway={this.handleCloseCommentMenu}>
|
||||||
|
<Grow in={openMenu!} id='comment-menu' style={{ transformOrigin: '0 0 0' }}>
|
||||||
|
<Paper>
|
||||||
|
<MenuList role='menu'>
|
||||||
|
<MenuItem className={classes.rightIconMenuItem}>Reply</MenuItem>
|
||||||
|
{this.props.isCommentOwner ? (<MenuItem className={classes.rightIconMenuItem} onClick={this.handleEditComment}>Edit</MenuItem>) : ''}
|
||||||
|
{(this.props.isCommentOwner || this.props.isPostOwner) ? (<MenuItem className={classes.rightIconMenuItem} onClick={(evt: any) => this.handleDelete(evt, comment.id, comment.postId)}>Delete</MenuItem>) : ''}
|
||||||
|
</MenuList>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Popper>
|
||||||
|
</Manager>
|
||||||
)
|
)
|
||||||
|
|
||||||
const Author = () => (
|
const Author = () => (
|
||||||
<div style={{ marginTop: '-11px' }}>
|
<div>
|
||||||
<span style={this.styles.author as any}>{comment.userDisplayName}</span><span style={{
|
<NavLink to={`/${userId}`}> <span style={this.styles.author as any}>{comment.userDisplayName}</span></NavLink><span style={{
|
||||||
fontWeight: 100,
|
fontWeight: 100,
|
||||||
fontSize: '10px'
|
fontSize: '8px'
|
||||||
}}>{moment.unix(comment.creationDate!).fromNow()}</span>
|
}}>{moment.unix(comment.creationDate!).fromNow()}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
const { userId, editorStatus } = comment
|
||||||
const commentBody = (
|
const commentBody = (
|
||||||
<p style={this.styles.commentBody as any}>{comment.text}</p>
|
<div style={{ outline: 'none', flex: 'auto', flexGrow: 1 }}>
|
||||||
|
{ editorStatus ? <TextField
|
||||||
|
placeholder={'Add a comment...'}
|
||||||
|
multiline
|
||||||
|
autoFocus
|
||||||
|
rowsMax='4'
|
||||||
|
InputProps={{
|
||||||
|
disableUnderline: true,
|
||||||
|
autoFocus: true,
|
||||||
|
fullWidth: true
|
||||||
|
}}
|
||||||
|
value={this.state.text}
|
||||||
|
onChange={this.handleOnChange}
|
||||||
|
className={classes.textField}
|
||||||
|
fullWidth={true}
|
||||||
|
/> : <div className={classNames('animate2-top10', classes.commentBody)}>{this.state.text}</div>}
|
||||||
|
|
||||||
|
<div style={{ display: (editorStatus ? 'flex' : 'none'), flexDirection: 'row-reverse' }}>
|
||||||
|
<Button color='primary' disabled={this.state.editDisabled}
|
||||||
|
style={{ float: 'right', clear: 'both', zIndex: 5, margin: '0px 5px 5px 0px', fontWeight: 400 }}
|
||||||
|
onClick={this.handleUpdateComment} > Update </Button>
|
||||||
|
<Button color='primary' style={this.styles.cancel as any} onClick={this.handleCancelEdit} > Cancel </Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {userId} = comment
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='animate-top' style={this.styles.comment} key={comment.id!}>
|
<div className='animate-top' key={comment.id!}>
|
||||||
<Paper zDepth={0} className='animate2-top10' style={{ position: 'relative', padding: '', display: (!this.state.display ? 'block' : 'none') }}>
|
<Paper elevation={0} className='animate2-top10'
|
||||||
<div style={{ marginLeft: '0px', padding: '16px 56px 0px 72px', position: 'relative' }}>
|
style={{ position: 'relative', padding: '', display: (!this.state.display ? 'block' : 'none') }}>
|
||||||
<NavLink to={`/${userId}`}><UserAvatarComponent fullName={this.props.fullName} fileName={this.props.avatar} style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', position: 'absolute', top: '8px', left: '16px' }} size={36} /></NavLink>
|
<Card elevation={0}>
|
||||||
<NavLink to={`/${userId}`}> <Author /></NavLink>
|
<CardHeader
|
||||||
{(!this.props.isCommentOwner && !this.props.isPostOwner && this.props.disableComments ) ? '' : (<RightIconMenu />)}
|
className={classes.header}
|
||||||
<div style={{ outline: 'none', marginLeft: '16px', flex: 'auto', flexGrow: 1 }}>
|
title={editorStatus ? '' : <Author />}
|
||||||
<textarea ref={this.textareaRef} className='animate2-top10' style={ Object.assign({}, this.styles.textarea, { display: (this.props.comment.editorStatus ? 'block' : 'none') })} onChange={this.handleOnChange} value={this.state.text!}></textarea>
|
subheader={commentBody}
|
||||||
<Linkify properties={{target: '_blank', style: {color: 'blue'}}}>
|
avatar={<NavLink to={`/${userId}`}><UserAvatar fullName={fullName!} fileName={avatar!} size={24} /></NavLink>}
|
||||||
<div ref={this.divCommentRef} className='animate2-top10' style={{ fontWeight: 100, fontSize: '14px', height: '100%', border: 'none', width: '100%', outline: 'none', resize: 'none', display: (!this.props.comment.editorStatus ? 'block' : 'none') }}>{this.state.text}</div>
|
action={(!this.props.isCommentOwner && !this.props.isPostOwner && this.props.disableComments) || editorStatus ? '' : (<RightIconMenu />)}
|
||||||
</Linkify>
|
>
|
||||||
</div>
|
</CardHeader>
|
||||||
</div>
|
|
||||||
<div style={{ display: (this.props.comment.editorStatus ? 'flex' : 'none'), flexDirection: 'row-reverse' }}>
|
</Card>
|
||||||
<FlatButton primary={true} disabled={this.state.editDisabled} label='Update' style={{ float: 'right', clear: 'both', zIndex: 5, margin: '0px 5px 5px 0px', fontWeight: 400 }} onClick={this.handleUpdateComment} />
|
|
||||||
<FlatButton primary={true} label='Cancel' style={this.styles.cancel as any} onClick={this.handleCancelEdit} />
|
|
||||||
</div>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -308,16 +396,13 @@ export class CommentComponent extends Component<ICommentComponentProps,ICommentC
|
|||||||
*/
|
*/
|
||||||
const mapDispatchToProps = (dispatch: any, ownProps: ICommentComponentProps) => {
|
const mapDispatchToProps = (dispatch: any, ownProps: ICommentComponentProps) => {
|
||||||
return {
|
return {
|
||||||
delete: (id: string| null, postId: string) => dispatch(commentActions.dbDeleteComment(id, postId)),
|
delete: (id: string | null, postId: string) => dispatch(commentActions.dbDeleteComment(id, postId)),
|
||||||
update: (comment: Comment) => {
|
update: (comment: Comment) => {
|
||||||
console.log('====================================')
|
|
||||||
console.log(comment)
|
|
||||||
console.log('====================================')
|
|
||||||
dispatch(commentActions.dbUpdateComment(comment))
|
dispatch(commentActions.dbUpdateComment(comment))
|
||||||
},
|
},
|
||||||
openEditor: () => dispatch(commentActions.openCommentEditor({ id: ownProps.comment.id, postId: ownProps.comment.postId })),
|
openEditor: () => dispatch(commentActions.openCommentEditor({ id: ownProps.comment.id, postId: ownProps.comment.postId })),
|
||||||
closeEditor: () => dispatch(commentActions.closeCommentEditor({ id: ownProps.comment.id, postId: ownProps.comment.postId })),
|
closeEditor: () => dispatch(commentActions.closeCommentEditor({ id: ownProps.comment.id, postId: ownProps.comment.postId })),
|
||||||
getUserInfo: () => dispatch(userActions.dbGetUserInfoByUserId(ownProps.comment.userId!,''))
|
getUserInfo: () => dispatch(userActions.dbGetUserInfoByUserId(ownProps.comment.userId!, ''))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +413,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICommentComponentProps) =>
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any, ownProps: any) => {
|
const mapStateToProps = (state: any, ownProps: any) => {
|
||||||
const {uid} = state.authorize
|
const { uid } = state.authorize
|
||||||
const avatar = state.user.info && state.user.info[ownProps.comment.userId] ? state.user.info[ownProps.comment.userId].avatar || '' : ''
|
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 fullName = state.user.info && state.user.info[ownProps.comment.userId] ? state.user.info[ownProps.comment.userId].fullName || '' : ''
|
||||||
return {
|
return {
|
||||||
@@ -341,4 +426,4 @@ const mapStateToProps = (state: any, ownProps: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(CommentComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(CommentComponent as any) as any)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export interface ICommentComponentProps {
|
|||||||
* @type {Function}
|
* @type {Function}
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
openEditor: Function
|
openEditor?: Function
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close comment editor
|
* Close comment editor
|
||||||
@@ -24,7 +24,7 @@ export interface ICommentComponentProps {
|
|||||||
* @type {Function}
|
* @type {Function}
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
closeEditor: () => any
|
closeEditor?: () => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current user is comment owner {true} or not {false}
|
* Current user is comment owner {true} or not {false}
|
||||||
@@ -32,7 +32,7 @@ export interface ICommentComponentProps {
|
|||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
isCommentOwner: boolean
|
isCommentOwner?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current user is post owner {true} or not {false}
|
* Current user is post owner {true} or not {false}
|
||||||
@@ -47,21 +47,21 @@ export interface ICommentComponentProps {
|
|||||||
*
|
*
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
update: (comment: Comment) => any
|
update?: (comment: Comment) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete comment
|
* Delete comment
|
||||||
*
|
*
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
delete: (id?: string| null, postId?: string) => any
|
delete?: (id?: string| null, postId?: string) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user profile
|
* Get user profile
|
||||||
*
|
*
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
getUserInfo: () => void
|
getUserInfo?: () => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User profile
|
* User profile
|
||||||
@@ -69,7 +69,7 @@ export interface ICommentComponentProps {
|
|||||||
* @type {{[userId: string]: Profile}}
|
* @type {{[userId: string]: Profile}}
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
info: {[userId: string]: Profile}
|
info?: {[userId: string]: Profile}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User full name
|
* User full name
|
||||||
@@ -77,7 +77,7 @@ export interface ICommentComponentProps {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
fullName: string
|
fullName?: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User avatar address
|
* User avatar address
|
||||||
@@ -85,7 +85,7 @@ export interface ICommentComponentProps {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof Comment
|
* @memberof Comment
|
||||||
*/
|
*/
|
||||||
avatar: string
|
avatar?: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writing comment on the post is disabled {true} or not false
|
* Writing comment on the post is disabled {true} or not false
|
||||||
@@ -93,6 +93,11 @@ export interface ICommentComponentProps {
|
|||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
disableComments: boolean
|
disableComments?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes: any
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export interface ICommentComponentState {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof ICommentComponentProps
|
* @memberof ICommentComponentProps
|
||||||
*/
|
*/
|
||||||
text?: string | null
|
text: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comment is in edit state {true} or not {false}
|
* Comment is in edit state {true} or not {false}
|
||||||
@@ -40,4 +40,9 @@ export interface ICommentComponentState {
|
|||||||
* @memberof ICommentComponentState
|
* @memberof ICommentComponentState
|
||||||
*/
|
*/
|
||||||
display?: boolean
|
display?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wheter comment menu is open
|
||||||
|
*/
|
||||||
|
openMenu?: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,25 +2,73 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
import { NavLink } from 'react-router-dom'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import Divider from 'material-ui/Divider'
|
import Divider from 'material-ui/Divider'
|
||||||
import { ListItem } from 'material-ui/List'
|
import { ListItemIcon, ListItemText, ListItem } from 'material-ui/List'
|
||||||
import { grey400, darkBlack, lightBlack, tealA400 } from 'material-ui/styles/colors'
|
import { grey, teal } from 'material-ui/colors'
|
||||||
import LinearProgress from 'material-ui/LinearProgress'
|
import { LinearProgress } from 'material-ui/Progress'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
import { Manager, Target, Popper } from 'react-popper'
|
||||||
|
import { Card, CardActions, CardHeader, CardMedia, CardContent } from 'material-ui'
|
||||||
|
import Grow from 'material-ui/transitions/Grow'
|
||||||
|
import ClickAwayListener from 'material-ui/utils/ClickAwayListener'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
import * as commentActions from 'actions/commentActions'
|
import * as commentActions from 'actions/commentActions'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import CommentListComponent from 'components/CommentList'
|
import CommentListComponent from 'components/CommentList'
|
||||||
import UserAvatarComponent from 'components/userAvatar'
|
import UserAvatar from 'components/userAvatar'
|
||||||
|
|
||||||
import { ICommentGroupComponentProps } from './ICommentGroupComponentProps'
|
import { ICommentGroupComponentProps } from './ICommentGroupComponentProps'
|
||||||
import { ICommentGroupComponentState } from './ICommentGroupComponentState'
|
import { ICommentGroupComponentState } from './ICommentGroupComponentState'
|
||||||
import { Comment } from 'core/domain/comments/comment'
|
import { Comment } from 'core/domain/comments/comment'
|
||||||
|
import { ServerRequestModel } from 'models/server';
|
||||||
|
import StringAPI from 'api/StringAPI';
|
||||||
|
import { ServerRequestType } from 'constants/serverRequestType';
|
||||||
|
import { ServerRequestStatusType } from 'actions/serverRequestStatusType';
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
textField: {
|
||||||
|
fontWeight: 100,
|
||||||
|
fontSize: '14px'
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
padding: '2px 3px 3px 10px'
|
||||||
|
},
|
||||||
|
commentBody: {
|
||||||
|
color: 'black',
|
||||||
|
fontWeight: 100,
|
||||||
|
fontSize: '12px',
|
||||||
|
height: '100%',
|
||||||
|
border: 'none',
|
||||||
|
width: '100%',
|
||||||
|
outline: 'none',
|
||||||
|
resize: 'none'
|
||||||
|
},
|
||||||
|
author: {
|
||||||
|
fontSize: '10px',
|
||||||
|
paddingRight: '10px',
|
||||||
|
fontWeight: 400,
|
||||||
|
color: 'rgba(0,0,0,0.87)',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
overflow: 'hidden'
|
||||||
|
|
||||||
|
},
|
||||||
|
noUnderline: {
|
||||||
|
display: 'none'
|
||||||
|
},
|
||||||
|
postButton: {
|
||||||
|
flexDirection: 'row-reverse'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
@@ -28,29 +76,29 @@ import { Comment } from 'core/domain/comments/comment'
|
|||||||
export class CommentGroupComponent extends Component<ICommentGroupComponentProps, ICommentGroupComponentState> {
|
export class CommentGroupComponent extends Component<ICommentGroupComponentProps, ICommentGroupComponentState> {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
/**
|
/**
|
||||||
* If it's true comment box will be open
|
* If it's true comment box will be open
|
||||||
*/
|
*/
|
||||||
open: PropTypes.bool,
|
open: PropTypes.bool,
|
||||||
/**
|
/**
|
||||||
* If it's true the comment is disable to write
|
* If it's true the comment is disable to write
|
||||||
*/
|
*/
|
||||||
disableComments: PropTypes.bool,
|
disableComments: PropTypes.bool,
|
||||||
/**
|
/**
|
||||||
* The post identifier which comment belong to
|
* The post identifier which comment belong to
|
||||||
*/
|
*/
|
||||||
postId: PropTypes.string,
|
postId: PropTypes.string,
|
||||||
/**
|
/**
|
||||||
* If it's true the post owner is the logged in user which this post be long to the comment
|
* If it's true the post owner is the logged in user which this post be long to the comment
|
||||||
*/
|
*/
|
||||||
isPostOwner: PropTypes.bool,
|
isPostOwner: PropTypes.bool,
|
||||||
/**
|
/**
|
||||||
* Toggle on show/hide comment by passing callback from parent component
|
* Toggle on show/hide comment by passing callback from parent component
|
||||||
*/
|
*/
|
||||||
onToggleRequest: PropTypes.func,
|
onToggleRequest: PropTypes.func,
|
||||||
/**
|
/**
|
||||||
* The user identifier of the post owner which comment belong to
|
* The user identifier of the post owner which comment belong to
|
||||||
*/
|
*/
|
||||||
ownerPostUserId: PropTypes.string
|
ownerPostUserId: PropTypes.string
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -66,11 +114,29 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
zIndex: 5
|
zIndex: 5
|
||||||
},
|
},
|
||||||
writeCommentTextField: {
|
writeCommentTextField: {
|
||||||
width: '100%'
|
width: '100%',
|
||||||
|
fontWeight: 100,
|
||||||
|
fontSize: '14px'
|
||||||
},
|
},
|
||||||
progressbar: {
|
progressbar: {
|
||||||
height: '1.5px',
|
height: '1.5px',
|
||||||
backgroundColor: 'rgb(245, 243, 243)'
|
backgroundColor: 'rgb(245, 243, 243)',
|
||||||
|
color: teal['A400']
|
||||||
|
},
|
||||||
|
secondaryText: {
|
||||||
|
fontSize: '13px',
|
||||||
|
lineHeight: '20px',
|
||||||
|
color: 'rgba(0,0,0,0.87)',
|
||||||
|
fontWeight: 300,
|
||||||
|
whiteSpace: 'pre-wrap'
|
||||||
|
},
|
||||||
|
primaryText: {
|
||||||
|
fontSize: '13px',
|
||||||
|
paddingRight: '10px',
|
||||||
|
fontWeight: 400,
|
||||||
|
color: 'rgba(0,0,0,0.87)',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
overflow: 'hidden'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +187,8 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
* @param {event} evt is an event passed by change comment text callback funciton
|
* @param {event} evt is an event passed by change comment text callback funciton
|
||||||
* @param {string} data is the comment text which user writes
|
* @param {string} data is the comment text which user writes
|
||||||
*/
|
*/
|
||||||
handleOnChange = (evt: any, data: any) => {
|
handleChange = (event: any) => {
|
||||||
|
const data = event.target.value
|
||||||
this.setState({ commentText: data })
|
this.setState({ commentText: data })
|
||||||
if (data.length === 0 || data.trim() === '') {
|
if (data.length === 0 || data.trim() === '') {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -142,10 +209,11 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
* @return {DOM} list of comments' DOM
|
* @return {DOM} list of comments' DOM
|
||||||
*/
|
*/
|
||||||
commentList = () => {
|
commentList = () => {
|
||||||
|
const {classes} = this.props
|
||||||
let comments = this.props.commentSlides
|
let comments = this.props.commentSlides
|
||||||
if (comments) {
|
if (comments) {
|
||||||
comments = _.fromPairs(_.toPairs(comments)
|
comments = _.fromPairs(_.toPairs(comments)
|
||||||
.sort((a: any, b: any) => parseInt(b[1].creationDate,10) - parseInt(a[1].creationDate,10)))
|
.sort((a: any, b: any) => parseInt(b[1].creationDate, 10) - parseInt(a[1].creationDate, 10)))
|
||||||
let parsedComments: Comment[] = []
|
let parsedComments: Comment[] = []
|
||||||
Object.keys(comments).forEach((commentId) => {
|
Object.keys(comments).forEach((commentId) => {
|
||||||
parsedComments.push({
|
parsedComments.push({
|
||||||
@@ -160,34 +228,41 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
parsedComments.push(parsedComments[0])
|
parsedComments.push(parsedComments[0])
|
||||||
}
|
}
|
||||||
return parsedComments.map((comment, index) => {
|
return parsedComments.map((comment, index) => {
|
||||||
const {userInfo} = this.props
|
const { userInfo } = this.props
|
||||||
|
|
||||||
const commentAvatar = userInfo && userInfo[comment.userId!] ? userInfo[comment.userId!].avatar || '' : ''
|
const commentAvatar = userInfo && userInfo[comment.userId!] ? userInfo[comment.userId!].avatar || '' : ''
|
||||||
const commentFullName = userInfo && userInfo[comment.userId!] ? userInfo[comment.userId!].fullName || '' : ''
|
const commentFullName = userInfo && userInfo[comment.userId!] ? userInfo[comment.userId!].fullName || '' : ''
|
||||||
|
|
||||||
return (<ListItem key={index} style={this.styles.commentItem as any} innerDivStyle={{ padding: '6px 16px 16px 72px' }}
|
const commentBody = (
|
||||||
leftAvatar={<UserAvatarComponent fullName={commentFullName} fileName={commentAvatar} style={{ top: '8px' }} size={36} />}
|
<div style={{ outline: 'none', flex: 'auto', flexGrow: 1 }}>
|
||||||
secondaryText={<div style={{ height: '' }}>
|
<div className={classNames('animate2-top10', classes.commentBody)} >
|
||||||
<span style={{
|
{comment.text}
|
||||||
fontSize: '13px',
|
</div>
|
||||||
paddingRight: '10px',
|
</div>
|
||||||
fontWeight: 400,
|
)
|
||||||
color: 'rgba(0,0,0,0.87)',
|
|
||||||
textOverflow: 'ellipsis',
|
const Author = () => (
|
||||||
overflow: 'hidden'
|
<div>
|
||||||
}}>
|
<NavLink to={`/${comment.userId!}`}> <span className={classes.author}>{comment.userDisplayName}</span></NavLink><span style={{
|
||||||
{comment.userDisplayName}:
|
fontWeight: 100,
|
||||||
</span>
|
fontSize: '8px'
|
||||||
<span style={{
|
}}>{moment.unix(comment.creationDate!).fromNow()}</span>
|
||||||
fontSize: '13px',
|
</div>
|
||||||
lineHeight: '20px',
|
)
|
||||||
color: 'rgba(0,0,0,0.87)',
|
return (
|
||||||
fontWeight: 300,
|
<Paper key={comment.id! + '-index:' + index} elevation={0} className='animate2-top10'>
|
||||||
whiteSpace: 'pre-wrap'
|
<Card elevation={0}>
|
||||||
}}>{comment.text}</span>
|
<CardHeader
|
||||||
</div>}
|
className={classes.header}
|
||||||
secondaryTextLines={2}
|
title={ <Author />}
|
||||||
/>
|
avatar={<UserAvatar fullName={commentFullName!} fileName={commentAvatar!} size={24} />}
|
||||||
|
subheader={commentBody}
|
||||||
|
>
|
||||||
|
</CardHeader>
|
||||||
|
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
</Paper>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -198,47 +273,62 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
const {comments} = this.props
|
const { comments, classes, postId, fullName, avatar, getCommentsRequest, open, commentSlides } = this.props
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comment list box
|
* Comment list box
|
||||||
*/
|
*/
|
||||||
const commentWriteBox = (<div>
|
const commentWriteBox = (<div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Paper zDepth={0} className='animate2-top10' style={{ position: 'relative', overflowY: 'auto', padding: '12px 16px', display: (this.props.open ? 'block' : 'none') }}>
|
<Paper key={postId! + '-commentwrite'} elevation={0} className='animate2-top10'>
|
||||||
|
<Card elevation={0}>
|
||||||
<div style={{ display: 'flex' }}>
|
<CardHeader
|
||||||
<UserAvatarComponent fullName={this.props.fullName!} fileName={this.props.avatar!} style={{ flex: 'none', margin: '4px 0px' }} size={36} />
|
className={classes.header}
|
||||||
<div style={{ outline: 'none', marginLeft: '16px', flex: 'auto', flexGrow: 1 }}>
|
avatar={<UserAvatar fullName={fullName!} fileName={avatar!} size={24} />}
|
||||||
<TextField
|
subheader={<TextField
|
||||||
value={this.state.commentText}
|
autoFocus
|
||||||
onChange={this.handleOnChange}
|
placeholder={'Add a comment...'}
|
||||||
hintText='Add a comment...'
|
multiline
|
||||||
underlineShow={false}
|
rowsMax='4'
|
||||||
multiLine={true}
|
InputProps={{
|
||||||
rows={1}
|
disableUnderline: true,
|
||||||
hintStyle={{ fontWeight: 100, fontSize: '14px' }}
|
autoFocus: true,
|
||||||
rowsMax={4}
|
fullWidth: true
|
||||||
textareaStyle={{ fontWeight: 100, fontSize: '14px' }}
|
}}
|
||||||
style={this.styles.writeCommentTextField}
|
value={this.state.commentText}
|
||||||
/>
|
onChange={this.handleChange}
|
||||||
</div>
|
className={classes.textField}
|
||||||
|
fullWidth={true}
|
||||||
|
/>}
|
||||||
|
>
|
||||||
|
</CardHeader>
|
||||||
|
<CardActions className={classes.postButton} >
|
||||||
|
<Button color='primary' disabled={this.state.postDisable} onClick={this.handlePostComment}>
|
||||||
|
Post
|
||||||
|
</Button>
|
||||||
|
</CardActions>
|
||||||
|
</Card>
|
||||||
|
</Paper>
|
||||||
</div>
|
</div>
|
||||||
<FlatButton primary={true} disabled={this.state.postDisable} label='Post' style={{ float: 'right', clear: 'both', zIndex: 5, margin: '0px 5px 5px 0px', fontWeight: 400 }} onClick={this.handlePostComment} />
|
)
|
||||||
</Paper>
|
|
||||||
</div>)
|
|
||||||
|
|
||||||
|
const showComments = ( comments && Object.keys(comments).length > 0
|
||||||
|
? (<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} />
|
||||||
|
</Paper>)
|
||||||
|
: '')
|
||||||
|
const loadComments = (( getCommentsRequest === undefined || (getCommentsRequest && getCommentsRequest!.status !== ServerRequestStatusType.OK)) ? <LinearProgress style={this.styles.progressbar} mode='indeterminate' /> : showComments)
|
||||||
/**
|
/**
|
||||||
* Return Elements
|
* Return Elements
|
||||||
*/
|
*/
|
||||||
return (
|
return (
|
||||||
<div>
|
<div key={postId + '-comments'}>
|
||||||
<div style={this.props.commentSlides && Object.keys(this.props.commentSlides).length > 0 ? { display: 'block' } : { display: 'none' }}>
|
<div style={commentSlides && Object.keys(commentSlides).length > 0 ? { display: 'block' } : { display: 'none' }}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Paper zDepth={0} className='animate-top' style={!this.props.open ? { display: 'block' } : { display: 'none' }}>
|
<Paper elevation={0} className='animate-top' style={!open ? { display: 'block' } : { display: 'none' }}>
|
||||||
|
|
||||||
<div style={{ position: 'relative', height: '60px' }} >
|
<div style={{ position: 'relative', height: '60px' }} >
|
||||||
<FlatButton label=' ' style={this.styles.toggleShowList} fullWidth={true} onClick={this.props.onToggleRequest} />
|
<Button style={this.styles.toggleShowList} fullWidth={true} onClick={this.props.onToggleRequest} > {' '}</Button>
|
||||||
|
|
||||||
<div className='comment__list-show'>
|
<div className='comment__list-show'>
|
||||||
{this.commentList()}
|
{this.commentList()}
|
||||||
@@ -247,20 +337,14 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
{
|
{
|
||||||
!comments
|
open ? loadComments : ''
|
||||||
? this.props.open ? <LinearProgress style={this.styles.progressbar} mode='indeterminate' color={tealA400} /> : ''
|
|
||||||
: (Object.keys(comments).length > 0
|
|
||||||
? (<Paper zDepth={0} style={this.props.open ? { display: 'block', padding: '0px 0px' } : { display: 'none', padding: '12px 16px' }}>
|
|
||||||
<CommentListComponent comments={comments} isPostOwner={this.props.isPostOwner} disableComments={this.props.disableComments}/>
|
|
||||||
</Paper>)
|
|
||||||
: '')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
!this.props.disableComments
|
(!this.props.disableComments && open )
|
||||||
? commentWriteBox
|
? commentWriteBox
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -276,7 +360,7 @@ export class CommentGroupComponent extends Component<ICommentGroupComponentProps
|
|||||||
const mapDispatchToProps = (dispatch: any, ownProps: ICommentGroupComponentProps) => {
|
const mapDispatchToProps = (dispatch: any, ownProps: ICommentGroupComponentProps) => {
|
||||||
return {
|
return {
|
||||||
send: (text: string, postId: string, callBack: Function) => {
|
send: (text: string, postId: string, callBack: Function) => {
|
||||||
dispatch(commentActions.dbAddComment(ownProps.ownerPostUserId,{
|
dispatch(commentActions.dbAddComment(ownProps.ownerPostUserId, {
|
||||||
postId: postId,
|
postId: postId,
|
||||||
text: text
|
text: text
|
||||||
}, callBack))
|
}, callBack))
|
||||||
@@ -291,11 +375,13 @@ const mapDispatchToProps = (dispatch: any, ownProps: ICommentGroupComponentProps
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any, ownProps: ICommentGroupComponentProps) => {
|
const mapStateToProps = (state: any, ownProps: ICommentGroupComponentProps) => {
|
||||||
const {post, user, authorize} = state
|
const { post, user, authorize, server } = state
|
||||||
const {ownerPostUserId, postId} = ownProps
|
const {request} = server
|
||||||
|
const { ownerPostUserId, postId } = ownProps
|
||||||
const commentSlides = post.userPosts[ownerPostUserId] && post.userPosts[ownerPostUserId][postId] ? post.userPosts[ownerPostUserId][postId].comments : {}
|
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
|
||||||
return {
|
return {
|
||||||
|
getCommentsRequest,
|
||||||
commentSlides,
|
commentSlides,
|
||||||
avatar: user.info && user.info[state.authorize.uid] ? user.info[authorize.uid].avatar || '' : '',
|
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 || '' : '',
|
fullName: user.info && user.info[state.authorize.uid] ? user.info[authorize.uid].fullName || '' : '',
|
||||||
@@ -305,4 +391,4 @@ const mapStateToProps = (state: any, ownProps: ICommentGroupComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(CommentGroupComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(CommentGroupComponent as any) as any)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Profile } from 'core/domain/users'
|
import { Profile } from 'core/domain/users'
|
||||||
import { Comment } from 'core/domain/comments'
|
import { Comment } from 'core/domain/comments'
|
||||||
|
import { ServerRequestModel } from 'models/server'
|
||||||
export interface ICommentGroupComponentProps {
|
export interface ICommentGroupComponentProps {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,4 +99,14 @@ export interface ICommentGroupComponentProps {
|
|||||||
*/
|
*/
|
||||||
send?: (commentText: string, postId: string, clearCommentWrite: () => void) => any
|
send?: (commentText: string, postId: string, clearCommentWrite: () => void) => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get post comments request payload
|
||||||
|
*/
|
||||||
|
getCommentsRequest?: ServerRequestModel
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { List, ListItem } from 'material-ui/List'
|
import List, { ListItem, ListItemText } from 'material-ui/List'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import CommentComponent from 'components/Comment'
|
import CommentComponent from 'components/Comment'
|
||||||
@@ -68,7 +68,7 @@ export class CommentListComponent extends Component<ICommentListComponentProps,
|
|||||||
|
|
||||||
return sortedComments.map((comment: Comment, index: number, array: Comment) => {
|
return sortedComments.map((comment: Comment, index: number, array: Comment) => {
|
||||||
|
|
||||||
return <CommentComponent key={comment.id} comment={comment} isPostOwner={this.props.isPostOwner} disableComments={this.props.disableComments}/>
|
return <CommentComponent key={comment.id!} comment={comment} isPostOwner={this.props.isPostOwner} disableComments={this.props.disableComments}/>
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -84,8 +84,7 @@ export class CommentListComponent extends Component<ICommentListComponentProps,
|
|||||||
const styles: any = {
|
const styles: any = {
|
||||||
list: {
|
list: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
maxHeight: 450,
|
maxHeight: 450
|
||||||
overflowY: 'auto'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,25 +2,33 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { grey400, darkBlack, lightBlack } from 'material-ui/styles/colors'
|
import { grey } from 'material-ui/colors'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'
|
import MoreVertIcon from 'material-ui-icons/moreVert'
|
||||||
import SvgCamera from 'material-ui/svg-icons/image/photo-camera'
|
import SvgCamera from 'material-ui-icons/photoCamera'
|
||||||
import IconMenu from 'material-ui/IconMenu'
|
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List'
|
||||||
import MenuItem from 'material-ui/MenuItem'
|
import Menu, { MenuList, MenuItem } from 'material-ui/Menu'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
import EventListener, { withOptions } from 'react-event-listener'
|
import EventListener, { withOptions } from 'react-event-listener'
|
||||||
import Dialog from 'material-ui/Dialog'
|
import Dialog, {
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
|
DialogTitle
|
||||||
|
} from 'material-ui/Dialog'
|
||||||
import Divider from 'material-ui/Divider'
|
import Divider from 'material-ui/Divider'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
|
import Input, { InputLabel } from 'material-ui/Input'
|
||||||
|
import { FormControl, FormHelperText } from 'material-ui/Form'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import ImgCover from 'components/imgCover'
|
import ImgCover from 'components/imgCover'
|
||||||
import UserAvatarComponent from 'components/userAvatar'
|
import UserAvatarComponent from 'components/userAvatar'
|
||||||
import ImageGallery from 'components/imageGallery'
|
import ImageGallery from 'components/imageGallery'
|
||||||
import DialogTitle from 'layouts/DialogTitle'
|
import AppDialogTitle from 'layouts/dialogTitle'
|
||||||
|
|
||||||
// - Import API
|
// - Import API
|
||||||
import FileAPI from 'api/FileAPI'
|
import FileAPI from 'api/FileAPI'
|
||||||
@@ -34,6 +42,12 @@ import { IEditProfileComponentProps } from './IEditProfileComponentProps'
|
|||||||
import { IEditProfileComponentState } from './IEditProfileComponentState'
|
import { IEditProfileComponentState } from './IEditProfileComponentState'
|
||||||
import { Profile } from 'core/domain/users'
|
import { Profile } from 'core/domain/users'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
dialogTitle: {
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*/
|
*/
|
||||||
@@ -277,20 +291,20 @@ export class EditProfileComponent extends Component<IEditProfileComponentProps,I
|
|||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
|
|
||||||
|
const {classes} = this.props
|
||||||
const iconButtonElement = (
|
const iconButtonElement = (
|
||||||
<IconButton style={this.state.isSmall ? this.styles.iconButtonSmall : this.styles.iconButton} iconStyle={this.state.isSmall ? this.styles.iconButtonSmall : this.styles.iconButton}
|
<IconButton style={this.state.isSmall ? this.styles.iconButtonSmall : this.styles.iconButton}>
|
||||||
touch={true}
|
<MoreVertIcon style={{...(this.state.isSmall ? this.styles.iconButtonSmall : this.styles.iconButton),color: grey[400]}} viewBox='10 0 24 24' />
|
||||||
>
|
|
||||||
<MoreVertIcon color={grey400} viewBox='10 0 24 24' />
|
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)
|
)
|
||||||
|
|
||||||
const RightIconMenu = () => (
|
const RightIconMenu = () => (
|
||||||
<IconMenu iconButtonElement={iconButtonElement}>
|
<div>
|
||||||
|
{iconButtonElement}
|
||||||
<MenuItem style={{ fontSize: '14px' }}>Reply</MenuItem>
|
<MenuItem style={{ fontSize: '14px' }}>Reply</MenuItem>
|
||||||
<MenuItem style={{ fontSize: '14px' }}>Edit</MenuItem>
|
<MenuItem style={{ fontSize: '14px' }}>Edit</MenuItem>
|
||||||
<MenuItem style={{ fontSize: '14px' }}>Delete</MenuItem>
|
<MenuItem style={{ fontSize: '14px' }}>Delete</MenuItem>
|
||||||
</IconMenu>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -299,15 +313,10 @@ export class EditProfileComponent extends Component<IEditProfileComponentProps,I
|
|||||||
{/* Edit profile dialog */}
|
{/* Edit profile dialog */}
|
||||||
<Dialog
|
<Dialog
|
||||||
key='Edit-Profile'
|
key='Edit-Profile'
|
||||||
modal={false}
|
|
||||||
open={this.props.open!}
|
open={this.props.open!}
|
||||||
onRequestClose={this.props.onRequestClose}
|
onClose={this.props.onRequestClose}
|
||||||
autoScrollBodyContent={true}
|
|
||||||
bodyStyle={{ backgroundColor: 'none', padding: 'none', borderTop: 'none', borderBottom: 'none' }}
|
|
||||||
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
|
|
||||||
contentStyle={{ backgroundColor: 'none', maxWidth: '450px', maxHeight: 'none', height: '100%' }}
|
|
||||||
style={{ backgroundColor: 'none', maxHeight: 'none', height: '100%' }}
|
|
||||||
>
|
>
|
||||||
|
<DialogContent>
|
||||||
{/* Banner */}
|
{/* Banner */}
|
||||||
<div style={{ position: 'relative' }}>
|
<div style={{ position: 'relative' }}>
|
||||||
<ImgCover width='100%' height='250px' borderRadius='2px' fileName={this.state.banner} />
|
<ImgCover width='100%' height='250px' borderRadius='2px' fileName={this.state.banner} />
|
||||||
@@ -323,7 +332,7 @@ export class EditProfileComponent extends Component<IEditProfileComponentProps,I
|
|||||||
<div className='left'>
|
<div className='left'>
|
||||||
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
||||||
{/* Avatar */}
|
{/* Avatar */}
|
||||||
<div className='g__circle-black' onClick={this.handleOpenAvatarGallery} style={{ position: 'absolute', left: '50%', display: 'inline-block', top: '52px', margin: '-18px' }}>
|
<div className='g__circle-black' onClick={this.handleOpenAvatarGallery} style={{zIndex: 1, position: 'absolute', left: '50%', display: 'inline-block', top: '52px', margin: '-18px' }}>
|
||||||
<SvgCamera style={{ fill: 'rgba(255, 255, 255, 0.88)', transform: 'translate(6px, 6px)' }} />
|
<SvgCamera style={{ fill: 'rgba(255, 255, 255, 0.88)', transform: 'translate(6px, 6px)' }} />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -340,61 +349,59 @@ export class EditProfileComponent extends Component<IEditProfileComponentProps,I
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Edit user information box*/}
|
{/* Edit user information box*/}
|
||||||
<Paper style={this.styles.paper} zDepth={1}>
|
<Paper style={this.styles.paper} elevation={1}>
|
||||||
<div style={this.styles.title as any}>Personal Information</div>
|
<div style={this.styles.title as any}>Personal Information</div>
|
||||||
<div style={this.styles.box}>
|
<div style={this.styles.box}>
|
||||||
<TextField
|
<FormControl aria-describedby='fullNameInputError'>
|
||||||
floatingLabelText='Full name'
|
<InputLabel htmlFor='fullNameInput'>Full name</InputLabel>
|
||||||
onChange={this.handleInputChange}
|
<Input id='fullNameInput'
|
||||||
name='fullNameInput'
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.fullNameInputError}
|
name='fullNameInput'
|
||||||
value={this.state.fullNameInput}
|
value={this.state.fullNameInput} />
|
||||||
/>
|
<FormHelperText id='fullNameInputError'>{this.state.fullNameInputError}</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div style={this.styles.box}>
|
<div style={this.styles.box}>
|
||||||
<TextField
|
<FormControl aria-describedby='tagLineInputError'>
|
||||||
floatingLabelText='Tag Line'
|
<InputLabel htmlFor='tagLineInput'>Tagline</InputLabel>
|
||||||
onChange={this.handleInputChange}
|
<Input id='tagLineInput'
|
||||||
name='tagLineInput'
|
onChange={this.handleInputChange}
|
||||||
value={this.state.tagLineInput}
|
name='tagLineInput'
|
||||||
/>
|
value={this.state.tagLineInput} />
|
||||||
|
<FormHelperText id='tagLineInputError'>{this.state.fullNameInputError}</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div style={this.styles.actions as any}>
|
<div style={this.styles.actions as any}>
|
||||||
<FlatButton label='CANCEL' onClick={this.props.onRequestClose} />
|
<Button onClick={this.props.onRequestClose} > CANCEL </Button>
|
||||||
<RaisedButton label='UPDATE' primary={true} onClick={this.handleUpdate} style={this.styles.updateButton} />
|
<Button raised color='primary' onClick={this.handleUpdate} style={this.styles.updateButton}> UPDATE </Button>
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
<div style={{ height: '16px' }}></div>
|
<div style={{ height: '16px' }}></div>
|
||||||
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
{/* Image gallery for banner*/}
|
{/* Image gallery for banner*/}
|
||||||
<Dialog
|
<Dialog
|
||||||
title={<DialogTitle title='Choose an banner image' onRequestClose={this.handleCloseBannerGallery} />}
|
|
||||||
modal={false}
|
|
||||||
open={this.state.openBanner}
|
open={this.state.openBanner}
|
||||||
contentStyle={this.styles.dialogGallery}
|
onClose={this.handleCloseBannerGallery}
|
||||||
onRequestClose={this.handleCloseBannerGallery}
|
|
||||||
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
|
|
||||||
autoDetectWindowHeight={false}
|
|
||||||
|
|
||||||
>
|
>
|
||||||
|
<DialogTitle className={classes.dialogTitle}>
|
||||||
|
<AppDialogTitle title='Choose an banner image' onRequestClose={this.handleCloseBannerGallery} />
|
||||||
|
</DialogTitle>
|
||||||
<ImageGallery set={this.handleRequestSetBanner} close={this.handleCloseBannerGallery} />
|
<ImageGallery set={this.handleRequestSetBanner} close={this.handleCloseBannerGallery} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
{/* Image gallery for avatar */}
|
{/* Image gallery for avatar */}
|
||||||
<Dialog
|
<Dialog
|
||||||
title={<DialogTitle title='Choose an avatar image' onRequestClose={this.handleCloseAvatarGallery} />}
|
|
||||||
modal={false}
|
|
||||||
open={this.state.openAvatar}
|
open={this.state.openAvatar}
|
||||||
contentStyle={this.styles.dialogGallery}
|
onClose={this.handleCloseAvatarGallery}
|
||||||
onRequestClose={this.handleCloseAvatarGallery}
|
|
||||||
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
|
|
||||||
autoDetectWindowHeight={false}
|
|
||||||
|
|
||||||
>
|
>
|
||||||
|
<DialogTitle className={classes.dialogTitle}>
|
||||||
|
<AppDialogTitle title='Choose an avatar image' onRequestClose={this.handleCloseAvatarGallery} />
|
||||||
|
</DialogTitle>
|
||||||
<ImageGallery set={this.handleRequestSetAvatar} close={this.handleCloseAvatarGallery} />
|
<ImageGallery set={this.handleRequestSetAvatar} close={this.handleCloseAvatarGallery} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
@@ -433,4 +440,4 @@ const mapStateToProps = (state: any, ownProps: IEditProfileComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(EditProfileComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(EditProfileComponent as any) as any)
|
||||||
|
|||||||
@@ -55,4 +55,9 @@ export interface IEditProfileComponentProps {
|
|||||||
* @memberof IEditProfileComponentProps
|
* @memberof IEditProfileComponentProps
|
||||||
*/
|
*/
|
||||||
onRequestClose?: () => void
|
onRequestClose?: () => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ import { NavLink, withRouter } from 'react-router-dom'
|
|||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
import * as authorizeActions from 'actions/authorizeActions'
|
import * as authorizeActions from 'actions/authorizeActions'
|
||||||
@@ -74,7 +73,7 @@ export class EmailVerificationComponent extends Component<IEmailVerificationComp
|
|||||||
}}>Green</h1>
|
}}>Green</h1>
|
||||||
|
|
||||||
<div className='animate-bottom'>
|
<div className='animate-bottom'>
|
||||||
<Paper style={paperStyle} zDepth={1} rounded={false} >
|
<Paper style={paperStyle} elevation={1} rounded={false} >
|
||||||
<div style={{ padding: '48px 40px 36px' }}>
|
<div style={{ padding: '48px 40px 36px' }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
paddingLeft: '40px',
|
paddingLeft: '40px',
|
||||||
@@ -94,8 +93,8 @@ export class EmailVerificationComponent extends Component<IEmailVerificationComp
|
|||||||
An verificiation email has been already sent to you. Please check your inbox. If you couldn't see the emai, please resend email verification.
|
An verificiation email has been already sent to you. Please check your inbox. If you couldn't see the emai, please resend email verification.
|
||||||
</p>
|
</p>
|
||||||
<div style={this.styles.buttons}>
|
<div style={this.styles.buttons}>
|
||||||
<RaisedButton style={this.styles.homeButton} label='Home' primary={true} onClick={() => this.props.homePage()} />
|
<Button raised style={this.styles.homeButton} label='Home' color='primary' onClick={() => this.props.homePage()} />
|
||||||
<RaisedButton label='Send Email Verification' primary={true} onClick={() => this.props.sendEmailVerification()} />
|
<Button raised label='Send Email Verification' color='primary' onClick={() => this.props.sendEmailVerification()} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ import { Route, Switch, withRouter, Redirect, NavLink } from 'react-router-dom'
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import Menu from 'material-ui/Menu'
|
import Menu from 'material-ui/Menu'
|
||||||
import MenuItem from 'material-ui/MenuItem'
|
import { MenuList, MenuItem } from 'material-ui/Menu'
|
||||||
|
import { ListItemIcon, ListItemText } from 'material-ui/List'
|
||||||
import Divider from 'material-ui/Divider'
|
import Divider from 'material-ui/Divider'
|
||||||
import SvgArrowLeft from 'material-ui/svg-icons/hardware/keyboard-arrow-left'
|
import SvgArrowLeft from 'material-ui-icons/keyboardArrowLeft'
|
||||||
import SvgHome from 'material-ui/svg-icons/action/home'
|
import SvgHome from 'material-ui-icons/home'
|
||||||
import SvgFeedback from 'material-ui/svg-icons/action/feedback'
|
import SvgFeedback from 'material-ui-icons/feedback'
|
||||||
import SvgSettings from 'material-ui/svg-icons/action/settings'
|
import SvgSettings from 'material-ui-icons/settings'
|
||||||
import SvgAccountCircle from 'material-ui/svg-icons/action/account-circle'
|
import SvgAccountCircle from 'material-ui-icons/accountCircle'
|
||||||
import SvgPeople from 'material-ui/svg-icons/social/people'
|
import SvgPeople from 'material-ui-icons/people'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import Sidebar from 'components/sidebar'
|
import Sidebar from 'components/sidebar'
|
||||||
@@ -105,7 +106,7 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount () {
|
componentWillMount () {
|
||||||
const {global, clearData, loadData, authed, defaultDataEnable, isVerifide, goTo } = this.props
|
const { global, clearData, loadData, authed, defaultDataEnable, isVerifide, goTo } = this.props
|
||||||
if (!authed) {
|
if (!authed) {
|
||||||
goTo!('/login')
|
goTo!('/login')
|
||||||
return
|
return
|
||||||
@@ -129,29 +130,71 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
|
|||||||
* @memberof Home
|
* @memberof Home
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
const {loaded, authed, loadDataStream, mergedPosts, hasMorePosts, showSendFeedback} = this.props
|
const { loaded, authed, loadDataStream, mergedPosts, hasMorePosts, showSendFeedback } = this.props
|
||||||
return (
|
return (
|
||||||
<div id='home'>
|
<div id='home'>
|
||||||
<HomeHeader sidebar={this.state.sidebarOpen} sidebarStatus={this.state.sidebarStatus} />
|
<HomeHeader sidebar={this.state.sidebarOpen} sidebarStatus={this.state.sidebarStatus} />
|
||||||
<Sidebar overlay={this.sidebarOverlay} open={this.sidebar} status={this.sidebarStatus}>
|
<Sidebar overlay={this.sidebarOverlay} open={this.sidebar} status={this.sidebarStatus}>
|
||||||
<SidebarContent>
|
<SidebarContent>
|
||||||
<Menu style={{ color: 'rgb(117, 117, 117)', width: '210px' }}>
|
<MenuList style={{ color: 'rgb(117, 117, 117)', width: '210px' }}>
|
||||||
{this.state.sidebarOverlay
|
{this.state.sidebarOverlay
|
||||||
? <div><MenuItem onClick={this.handleCloseSidebar} primaryText={<span style={{ color: 'rgb(117, 117, 117)' }} className='sidebar__title'>Green</span>} rightIcon={<SvgArrowLeft viewBox='0 3 24 24' style={{ color: '#fff', marginLeft: '15px', width: '32px', height: '32px', cursor: 'pointer' }} />} /><Divider /></div>
|
? <div>
|
||||||
|
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<SvgArrowLeft viewBox='0 3 24 24' style={{ color: '#fff', marginLeft: '15px', width: '32px', height: '32px', cursor: 'pointer' }} />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText inset
|
||||||
|
primary={<span style={{ color: 'rgb(117, 117, 117)' }}
|
||||||
|
className='sidebar__title'>Green</span>} />
|
||||||
|
</MenuItem>
|
||||||
|
<Divider /></div>
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
<NavLink to='/'><MenuItem primaryText='Home' style={{ color: 'rgb(117, 117, 117)' }} leftIcon={<SvgHome />} /></NavLink>
|
<NavLink to='/'>
|
||||||
<NavLink to={`/${this.props.uid}`}><MenuItem primaryText='Profile' style={{ color: 'rgb(117, 117, 117)' }} leftIcon={<SvgAccountCircle />} /></NavLink>
|
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
|
||||||
<NavLink to='/people'><MenuItem primaryText='People' style={{ color: 'rgb(117, 117, 117)' }} leftIcon={<SvgPeople />} /></NavLink>
|
<ListItemIcon>
|
||||||
|
<SvgHome />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText inset primary='Home' />
|
||||||
|
</MenuItem>
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to={`/${this.props.uid}`}>
|
||||||
|
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<SvgAccountCircle />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText inset primary='Profile' />
|
||||||
|
</MenuItem>
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to='/people'>
|
||||||
|
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<SvgPeople />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText inset primary='People' />
|
||||||
|
</MenuItem>
|
||||||
|
</NavLink>
|
||||||
<Divider />
|
<Divider />
|
||||||
<NavLink to='/settings'><MenuItem primaryText='Settings' style={{ color: 'rgb(117, 117, 117)' }} leftIcon={<SvgSettings />} /></NavLink>
|
<NavLink to='/settings'>
|
||||||
<MenuItem primaryText='Send feedback' onClick={() => showSendFeedback()} style={{ color: 'rgb(117, 117, 117)' }} leftIcon={<SvgFeedback />} />
|
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
|
||||||
</Menu>
|
<ListItemIcon>
|
||||||
|
<SvgSettings />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText inset primary='Settings' />
|
||||||
|
</MenuItem>
|
||||||
|
</NavLink>
|
||||||
|
<MenuItem onClick={() => showSendFeedback()} style={{ color: 'rgb(117, 117, 117)' }}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<SvgFeedback />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText inset primary='Send feedback' />
|
||||||
|
</MenuItem>
|
||||||
|
</MenuList>
|
||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
|
|
||||||
<SidebarMain>
|
<SidebarMain>
|
||||||
<HomeRouter enabled={loaded!} data={{ mergedPosts, loadDataStream, hasMorePosts}} />
|
<HomeRouter enabled={loaded!} data={{ mergedPosts, loadDataStream, hasMorePosts }} />
|
||||||
</SidebarMain>
|
</SidebarMain>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
||||||
@@ -166,7 +209,7 @@ const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
loadDataStream:
|
loadDataStream:
|
||||||
(page: number, limit: number) => dispatch(postActions.dbGetPosts(page,limit)),
|
(page: number, limit: number) => dispatch(postActions.dbGetPosts(page, limit)),
|
||||||
loadData: () => {
|
loadData: () => {
|
||||||
dispatch(postActions.dbGetPosts())
|
dispatch(postActions.dbGetPosts())
|
||||||
dispatch(imageGalleryActions.dbGetImageGallery())
|
dispatch(imageGalleryActions.dbGetImageGallery())
|
||||||
@@ -216,9 +259,9 @@ const mapStateToProps = (state: any, ownProps: IHomeComponentProps) => {
|
|||||||
const hasMorePosts = post.stream.hasMoreData
|
const hasMorePosts = post.stream.hasMoreData
|
||||||
Object.keys(followingUsers).forEach((userId) => {
|
Object.keys(followingUsers).forEach((userId) => {
|
||||||
let newPosts = post.userPosts ? post.userPosts[userId] : {}
|
let newPosts = post.userPosts ? post.userPosts[userId] : {}
|
||||||
_.merge(mergedPosts,newPosts)
|
_.merge(mergedPosts, newPosts)
|
||||||
})
|
})
|
||||||
_.merge(mergedPosts,posts)
|
_.merge(mergedPosts, posts)
|
||||||
return {
|
return {
|
||||||
authed: authorize.authed,
|
authed: authorize.authed,
|
||||||
isVerifide: authorize.isVerifide,
|
isVerifide: authorize.isVerifide,
|
||||||
|
|||||||
@@ -2,17 +2,20 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink } from 'react-router-dom'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import SvgDehaze from 'material-ui/svg-icons/image/dehaze'
|
import SvgDehaze from 'material-ui-icons/dehaze'
|
||||||
import { green700, grey400, blue500 } from 'material-ui/styles/colors'
|
import { grey, blue } from 'material-ui/colors'
|
||||||
import { Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle } from 'material-ui/Toolbar'
|
import Toolbar from 'material-ui/Toolbar'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import Popover from 'material-ui/Popover'
|
||||||
import Popover, { PopoverAnimationVertical } from 'material-ui/Popover'
|
import AppBar from 'material-ui/AppBar'
|
||||||
import Menu from 'material-ui/Menu'
|
import Menu, { MenuList, MenuItem } from 'material-ui/Menu'
|
||||||
import MenuItem from 'material-ui/MenuItem'
|
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import NotificationsIcon from 'material-ui/svg-icons/social/notifications'
|
import NotificationsIcon from 'material-ui-icons/notifications'
|
||||||
import EventListener, { withOptions } from 'react-event-listener'
|
import EventListener, { withOptions } from 'react-event-listener'
|
||||||
|
import Tooltip from 'material-ui/Tooltip'
|
||||||
|
import Typography from 'material-ui/Typography'
|
||||||
|
import { Manager, Target, Popper } from 'react-popper'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
|
||||||
// - Import components
|
// - Import components
|
||||||
import UserAvatarComponent from 'components/userAvatar'
|
import UserAvatarComponent from 'components/userAvatar'
|
||||||
@@ -24,20 +27,19 @@ import { authorizeActions } from 'actions'
|
|||||||
import { IHomeHeaderComponentProps } from './IHomeHeaderComponentProps'
|
import { IHomeHeaderComponentProps } from './IHomeHeaderComponentProps'
|
||||||
import { IHomeHeaderComponentState } from './IHomeHeaderComponentState'
|
import { IHomeHeaderComponentState } from './IHomeHeaderComponentState'
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
root: {
|
||||||
|
backgroundColor: '#a5792a'
|
||||||
|
},
|
||||||
|
flex: {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// - Create HomeHeader component class
|
// - Create HomeHeader component class
|
||||||
export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHomeHeaderComponentState> {
|
export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps, IHomeHeaderComponentState> {
|
||||||
|
|
||||||
styles = {
|
styles = {
|
||||||
toolbarStyle: {
|
|
||||||
transition: 'all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms',
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
fontFamily: 'Roboto, sans-serif',
|
|
||||||
position: 'fixed',
|
|
||||||
zIndex: '1101',
|
|
||||||
width: '100%',
|
|
||||||
top: '0px',
|
|
||||||
boxShadow: '0 1px 8px rgba(0,0,0,.3)'
|
|
||||||
},
|
|
||||||
avatarStyle: {
|
avatarStyle: {
|
||||||
margin: 5,
|
margin: 5,
|
||||||
cursor: 'pointer'
|
cursor: 'pointer'
|
||||||
@@ -49,7 +51,7 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHo
|
|||||||
* Component constructor
|
* Component constructor
|
||||||
* @param {object} props is an object properties of component
|
* @param {object} props is an object properties of component
|
||||||
*/
|
*/
|
||||||
constructor (props: IHomeHeaderComponentProps) {
|
constructor(props: IHomeHeaderComponentProps) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
// Default state
|
// Default state
|
||||||
@@ -89,10 +91,10 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHo
|
|||||||
// On click toggle sidebar
|
// On click toggle sidebar
|
||||||
onToggleSidebar = () => {
|
onToggleSidebar = () => {
|
||||||
if (this.props.sidebarStatus) {
|
if (this.props.sidebarStatus) {
|
||||||
this.props.sidebar!(false,'onToggle')
|
this.props.sidebar!(false, 'onToggle')
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.props.sidebar!(true,'onToggle')
|
this.props.sidebar!(true, 'onToggle')
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,9 +122,6 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHo
|
|||||||
* @memberof HomeHeader
|
* @memberof HomeHeader
|
||||||
*/
|
*/
|
||||||
handleAvatarTouchTap = (event: any) => {
|
handleAvatarTouchTap = (event: any) => {
|
||||||
// This prevents ghost click.
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
openAvatarMenu: true,
|
openAvatarMenu: true,
|
||||||
anchorEl: event.currentTarget
|
anchorEl: event.currentTarget
|
||||||
@@ -147,7 +146,8 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHo
|
|||||||
*/
|
*/
|
||||||
handleRequestClose = () => {
|
handleRequestClose = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
openAvatarMenu: false
|
openAvatarMenu: false,
|
||||||
|
anchorEl: null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,69 +183,79 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps,IHo
|
|||||||
|
|
||||||
// Render app DOM component
|
// Render app DOM component
|
||||||
render () {
|
render () {
|
||||||
|
const { classes } = this.props
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<Toolbar style={this.styles.toolbarStyle as any}>
|
<AppBar position='fixed' color='secondary'>
|
||||||
<EventListener
|
<Toolbar>
|
||||||
target='window'
|
<EventListener
|
||||||
onResize={this.handleResize}
|
target='window'
|
||||||
onKeyUp={this.handleKeyUp}
|
onResize={this.handleResize}
|
||||||
/>
|
onKeyUp={this.handleKeyUp}
|
||||||
{/* Left side */}
|
/>
|
||||||
<ToolbarGroup firstChild={true}>
|
{/* Left side */}
|
||||||
|
|
||||||
<IconButton iconStyle={{ color: '#fff' }} onClick={this.onToggleSidebar} >
|
<IconButton onClick={this.onToggleSidebar} >
|
||||||
<SvgDehaze style={{ color: '#fff', marginLeft: '15px', cursor: 'pointer' }} />
|
<SvgDehaze color='primary' style={{ cursor: 'pointer' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{/* Header title */}
|
{/* Header title */}
|
||||||
<ToolbarTitle style={{ color: '#fff', marginLeft: '15px' }} text='Green' />
|
<Typography type='title' color='primary' style={{ marginLeft: '15px' }} >
|
||||||
{this.state.showTitle ? <div className='homeHeader__page'>{this.props.title}</div> : ''}
|
Green
|
||||||
</ToolbarGroup>
|
</Typography>
|
||||||
<ToolbarGroup>
|
<div className='homeHeader__title-root'>
|
||||||
|
{this.state.showTitle ? <div className='homeHeader__title'>{this.props.title}</div> : ''}
|
||||||
|
</div>
|
||||||
|
|
||||||
</ToolbarGroup>
|
{/* Notification */}
|
||||||
|
|
||||||
{/* Notification */}
|
|
||||||
<ToolbarGroup lastChild={true}>
|
|
||||||
<div className='homeHeader__right'>
|
<div className='homeHeader__right'>
|
||||||
{this.props.notifyCount! > 0 ? (<IconButton tooltip='Notifications' onTouchTap={this.handleNotifyTouchTap}>
|
<Manager>
|
||||||
<div className='homeHeader__notify'>
|
<Target>
|
||||||
<div className='title'>{this.props.notifyCount}</div>
|
{this.props.notifyCount! > 0 ? (
|
||||||
</div>
|
<Tooltip title='Notifications'>
|
||||||
</IconButton>)
|
<IconButton onClick={this.handleNotifyTouchTap}>
|
||||||
|
<div className='homeHeader__notify'>
|
||||||
: (<IconButton tooltip='Notifications' onTouchTap={this.handleNotifyTouchTap}>
|
<div className='title'>{this.props.notifyCount}</div>
|
||||||
<NotificationsIcon color='rgba(255, 255, 255, 0.87)' />
|
</div>
|
||||||
</IconButton>)}
|
</IconButton>
|
||||||
<Notify open={this.state.openNotifyMenu} anchorEl={this.state.anchorEl} onRequestClose={this.handleCloseNotify}/>
|
</Tooltip>)
|
||||||
|
: (<Tooltip title='Notifications'>
|
||||||
|
<IconButton onClick={this.handleNotifyTouchTap}>
|
||||||
|
<NotificationsIcon style={{ color: 'rgba(255, 255, 255, 0.87)' }} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>)}
|
||||||
|
</Target>
|
||||||
|
<Notify open={this.state.openNotifyMenu} anchorEl={this.state.anchorEl} onRequestClose={this.handleCloseNotify} />
|
||||||
|
</Manager>
|
||||||
|
|
||||||
{/* User avatar*/}
|
{/* User avatar*/}
|
||||||
<UserAvatarComponent
|
<UserAvatarComponent
|
||||||
onTouchTap={this.handleAvatarTouchTap}
|
onClick={this.handleAvatarTouchTap}
|
||||||
fullName={this.props.fullName!}
|
fullName={this.props.fullName!}
|
||||||
fileName={this.props.avatar!}
|
fileName={this.props.avatar!}
|
||||||
size={32}
|
size={32}
|
||||||
style={this.styles.avatarStyle}
|
style={this.styles.avatarStyle}
|
||||||
/>
|
/>
|
||||||
<Popover
|
|
||||||
|
<Menu
|
||||||
open={this.state.openAvatarMenu}
|
open={this.state.openAvatarMenu}
|
||||||
anchorEl={this.state.anchorEl}
|
anchorEl={this.state.anchorEl!}
|
||||||
anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}
|
anchorOrigin={{
|
||||||
targetOrigin={{ horizontal: 'left', vertical: 'top' }}
|
vertical: 'top',
|
||||||
onRequestClose={this.handleRequestClose}
|
horizontal: 'right'
|
||||||
>
|
}}
|
||||||
<Menu>
|
transformOrigin={{
|
||||||
<MenuItem style={{ backgroundColor: 'white', color: blue500, fontSize: '14px' }} primaryText='MY ACCOUNT' />
|
vertical: 'top',
|
||||||
<MenuItem primaryText='LOGOUT' style={{ fontSize: '14px' }} onClick={this.handleLogout.bind(this)} />
|
horizontal: 'right'
|
||||||
|
}}
|
||||||
|
onClose={this.handleRequestClose}>
|
||||||
|
<MenuItem style={{ backgroundColor: 'white', color: blue[500], fontSize: '14px' }} > MY ACCOUNT </MenuItem>
|
||||||
|
<MenuItem style={{ fontSize: '14px' }} onClick={this.handleLogout.bind(this)} > LOGOUT </MenuItem>
|
||||||
|
|
||||||
</Menu>
|
</Menu>
|
||||||
</Popover>
|
|
||||||
</div>
|
</div>
|
||||||
</ToolbarGroup>
|
|
||||||
|
|
||||||
</Toolbar>
|
|
||||||
|
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar >
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,10 +271,10 @@ const mapDispatchToProps = (dispatch: Function, ownProps: IHomeHeaderComponentPr
|
|||||||
const mapStateToProps = (state: any, ownProps: IHomeHeaderComponentProps) => {
|
const mapStateToProps = (state: any, ownProps: IHomeHeaderComponentProps) => {
|
||||||
|
|
||||||
let notifyCount = state.notify.userNotifies
|
let notifyCount = state.notify.userNotifies
|
||||||
? Object
|
? Object
|
||||||
.keys(state.notify.userNotifies)
|
.keys(state.notify.userNotifies)
|
||||||
.filter((key) => !state.notify.userNotifies[key].isSeen).length
|
.filter((key) => !state.notify.userNotifies[key].isSeen).length
|
||||||
: 0
|
: 0
|
||||||
return {
|
return {
|
||||||
avatar: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].avatar : '',
|
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 : '',
|
fullName: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].fullName : '',
|
||||||
@@ -274,4 +284,4 @@ const mapStateToProps = (state: any, ownProps: IHomeHeaderComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(HomeHeaderComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(HomeHeaderComponent as any) as any)
|
||||||
|
|||||||
@@ -60,4 +60,9 @@ export interface IHomeHeaderComponentProps {
|
|||||||
* @memberof IHomeHeaderComponentProps
|
* @memberof IHomeHeaderComponentProps
|
||||||
*/
|
*/
|
||||||
sidebar?: (status: boolean, source: string) => void
|
sidebar?: (status: boolean, source: string) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Material ui theme style
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,5 +31,5 @@ export interface IHomeHeaderComponentState {
|
|||||||
* @type {*}
|
* @type {*}
|
||||||
* @memberof IHomeHeaderComponentState
|
* @memberof IHomeHeaderComponentState
|
||||||
*/
|
*/
|
||||||
anchorEl?: HTMLElement
|
anchorEl?: HTMLElement | null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,16 +2,14 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { GridList, GridTile } from 'material-ui/GridList'
|
import GridList, { GridListTile, GridListTileBar } from 'material-ui/GridList'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import Subheader from 'material-ui/Subheader'
|
import StarBorder from 'material-ui-icons/starBorder'
|
||||||
import StarBorder from 'material-ui/svg-icons/toggle/star-border'
|
import Button from 'material-ui/Button'
|
||||||
import FloatingActionButton from 'material-ui/FloatingActionButton'
|
import SvgUpload from 'material-ui-icons/cloudUpload'
|
||||||
import SvgUpload from 'material-ui/svg-icons/file/cloud-upload'
|
import SvgAddImage from 'material-ui-icons/addAPhoto'
|
||||||
import SvgAddImage from 'material-ui/svg-icons/image/add-a-photo'
|
import SvgDelete from 'material-ui-icons/delete'
|
||||||
import SvgDelete from 'material-ui/svg-icons/action/delete'
|
import { grey } from 'material-ui/colors'
|
||||||
import { grey200, grey600 } from 'material-ui/styles/colors'
|
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
|
||||||
import uuid from 'uuid'
|
import uuid from 'uuid'
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
@@ -52,7 +50,8 @@ export class ImageGalleryComponent extends Component<IImageGalleryComponentProps
|
|||||||
overflowY: 'auto'
|
overflowY: 'auto'
|
||||||
},
|
},
|
||||||
uploadButton: {
|
uploadButton: {
|
||||||
verticalAlign: 'middle'
|
verticalAlign: 'middle',
|
||||||
|
fontWeight: 100
|
||||||
},
|
},
|
||||||
uploadInput: {
|
uploadInput: {
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
@@ -66,11 +65,13 @@ export class ImageGalleryComponent extends Component<IImageGalleryComponentProps
|
|||||||
},
|
},
|
||||||
deleteImage: {
|
deleteImage: {
|
||||||
marginLeft: '5px',
|
marginLeft: '5px',
|
||||||
cursor: 'pointer'
|
cursor: 'pointer',
|
||||||
|
color: 'white'
|
||||||
},
|
},
|
||||||
addImage: {
|
addImage: {
|
||||||
marginRight: '5px',
|
marginRight: '5px',
|
||||||
cursor: 'pointer'
|
cursor: 'pointer',
|
||||||
|
color: 'white'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +126,7 @@ export class ImageGalleryComponent extends Component<IImageGalleryComponentProps
|
|||||||
|
|
||||||
const { resizedImage, fileName } = event.detail
|
const { resizedImage, fileName } = event.detail
|
||||||
const {uploadImage} = this.props
|
const {uploadImage} = this.props
|
||||||
uploadImage(resizedImage,fileName)
|
uploadImage!(resizedImage,fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,11 +151,9 @@ export class ImageGalleryComponent extends Component<IImageGalleryComponentProps
|
|||||||
|
|
||||||
return this.props.images!.map((image: Image, index) => {
|
return this.props.images!.map((image: Image, index) => {
|
||||||
|
|
||||||
return (<GridTile
|
return (
|
||||||
|
<GridListTile
|
||||||
key={image.id!}
|
key={image.id!}
|
||||||
title={<SvgDelete hoverColor={grey200} color='white' style={this.styles.deleteImage as any} onClick={evt => this.handleDeleteImage(evt, image.id!)} />}
|
|
||||||
subtitle={<span></span>}
|
|
||||||
actionIcon={<SvgAddImage hoverColor={grey200} color='white' style={this.styles.addImage as any} onClick={evt => this.handleSetImage(evt, image.URL,image.fullPath)} />}
|
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div style={{ overflowY: 'hidden', overflowX: 'auto' }}>
|
<div style={{ overflowY: 'hidden', overflowX: 'auto' }}>
|
||||||
@@ -171,7 +170,15 @@ export class ImageGalleryComponent extends Component<IImageGalleryComponentProps
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</GridTile>)
|
<GridListTileBar
|
||||||
|
title={<SvgDelete style={this.styles.deleteImage as any} onClick={evt => this.handleDeleteImage(evt, image.id!)} />}
|
||||||
|
titlePosition='top'
|
||||||
|
actionIcon={
|
||||||
|
<SvgAddImage style={this.styles.addImage as any} onClick={evt => this.handleSetImage(evt, image.URL,image.fullPath)} />
|
||||||
|
}
|
||||||
|
actionPosition='left'
|
||||||
|
/>
|
||||||
|
</GridListTile>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,21 +200,24 @@ export class ImageGalleryComponent extends Component<IImageGalleryComponentProps
|
|||||||
cellHeight={180}
|
cellHeight={180}
|
||||||
style={this.styles.gridList as any}
|
style={this.styles.gridList as any}
|
||||||
>
|
>
|
||||||
<GridTile >
|
<GridListTile key='upload-image-gallery' >
|
||||||
|
|
||||||
<div style={{ display: 'flex', backgroundColor: 'rgba(222, 222, 222, 0.52)', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
|
<div style={{ display: 'flex', backgroundColor: 'rgba(222, 222, 222, 0.52)', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
|
||||||
|
|
||||||
<FlatButton
|
<input
|
||||||
label='Upload Photo'
|
accept='image/*'
|
||||||
labelStyle={{ fontWeight: 100 }}
|
style={this.styles.uploadInput as any}
|
||||||
labelPosition='before'
|
id='raised-button-file'
|
||||||
style={this.styles.uploadButton}
|
onChange={this.onFileChange}
|
||||||
containerElement='label'
|
type='file'
|
||||||
>
|
/>
|
||||||
<input type='file' onChange={this.onFileChange} accept='image/*' style={this.styles.uploadInput as any} />
|
<label htmlFor='raised-button-file'>
|
||||||
</FlatButton>
|
<Button raised component='span' style={this.styles.uploadButton as any}>
|
||||||
|
Upload
|
||||||
|
</Button>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</GridTile>
|
</GridListTile>
|
||||||
{this.imageList()}
|
{this.imageList()}
|
||||||
</GridList>
|
</GridList>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,4 +16,9 @@ export interface IImgComponentProps {
|
|||||||
*/
|
*/
|
||||||
style?: {}
|
style?: {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import SvgImage from 'material-ui/svg-icons/image/image'
|
import SvgImage from 'material-ui-icons/image'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
|
|
||||||
@@ -13,6 +14,15 @@ import * as imageGalleryActions from 'actions/imageGalleryActions'
|
|||||||
import { IImgComponentProps } from './IImgComponentProps'
|
import { IImgComponentProps } from './IImgComponentProps'
|
||||||
import { IImgComponentState } from './IImgComponentState'
|
import { IImgComponentState } from './IImgComponentState'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
image: {
|
||||||
|
verticalAlign: 'top',
|
||||||
|
maxWidth: '100%',
|
||||||
|
minWidth: '100%',
|
||||||
|
width: '100%'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*/
|
*/
|
||||||
@@ -77,9 +87,10 @@ export class ImgComponent extends Component<IImgComponentProps,IImgComponentStat
|
|||||||
|
|
||||||
let { fileName, style } = this.props
|
let { fileName, style } = this.props
|
||||||
let { isImageLoaded } = this.state
|
let { isImageLoaded } = this.state
|
||||||
|
const {classes} = this.props
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<img onLoad={this.handleLoadImage} src={fileName || ''} style={isImageLoaded ? style : { display: 'none' }} />
|
<img className={classes.image} onLoad={this.handleLoadImage} src={fileName || ''} style={isImageLoaded ? style : { display: 'none' }} />
|
||||||
<div style={Object.assign({},{ backgroundColor: 'white' }, isImageLoaded ? { display: 'none' } : this.styles.loding) }>
|
<div style={Object.assign({},{ backgroundColor: 'white' }, isImageLoaded ? { display: 'none' } : this.styles.loding) }>
|
||||||
<div style={this.styles.loadingContent as any}>
|
<div style={this.styles.loadingContent as any}>
|
||||||
<SvgImage style={this.styles.loadingImage} />
|
<SvgImage style={this.styles.loadingImage} />
|
||||||
@@ -117,4 +128,4 @@ const mapStateToProps = (state: any, ownProps: IImgComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ImgComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(ImgComponent as any)as any)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import SvgImage from 'material-ui/svg-icons/image/image'
|
import SvgImage from 'material-ui-icons/image'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
|
|
||||||
|
|||||||
@@ -21,4 +21,9 @@ export interface ILoginComponentProps {
|
|||||||
* @memberof ILoginComponentProps
|
* @memberof ILoginComponentProps
|
||||||
*/
|
*/
|
||||||
signupPage?: () => any
|
signupPage?: () => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,25 +5,35 @@ import { NavLink, withRouter } from 'react-router-dom'
|
|||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import FontIcon from 'material-ui/FontIcon'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import Divider from 'material-ui/Divider'
|
import Divider from 'material-ui/Divider'
|
||||||
import ActionAndroid from 'material-ui/svg-icons/action/android'
|
import ActionAndroid from 'material-ui-icons/android'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
import * as authorizeActions from 'actions/authorizeActions'
|
import * as authorizeActions from 'actions/authorizeActions'
|
||||||
import { ILoginComponentProps } from './ILoginComponentProps'
|
import { ILoginComponentProps } from './ILoginComponentProps'
|
||||||
import { ILoginComponentState } from './ILoginComponentState'
|
import { ILoginComponentState } from './ILoginComponentState'
|
||||||
import { firebaseAuth } from 'data/firebaseClient'
|
|
||||||
import { OAuthType } from 'core/domain/authorize'
|
import { OAuthType } from 'core/domain/authorize'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
textField: {
|
||||||
|
minWidth: 280,
|
||||||
|
marginTop: 20
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// - Create Login component class
|
// - Create Login component class
|
||||||
export class LoginComponent extends Component<ILoginComponentProps,ILoginComponentState> {
|
export class LoginComponent extends Component<ILoginComponentProps,ILoginComponentState> {
|
||||||
|
|
||||||
styles = {
|
styles = {
|
||||||
singinOptions: {
|
singinOptions: {
|
||||||
paddingBottom: 10
|
paddingBottom: 10,
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
display: 'flex'
|
||||||
},
|
},
|
||||||
divider: {
|
divider: {
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
@@ -124,6 +134,7 @@ export class LoginComponent extends Component<ILoginComponentProps,ILoginCompone
|
|||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
|
const {classes} = this.props
|
||||||
|
|
||||||
const paperStyle = {
|
const paperStyle = {
|
||||||
minHeight: 370,
|
minHeight: 370,
|
||||||
@@ -148,7 +159,7 @@ export class LoginComponent extends Component<ILoginComponentProps,ILoginCompone
|
|||||||
}}>Green</h1>
|
}}>Green</h1>
|
||||||
|
|
||||||
<div className='animate-bottom'>
|
<div className='animate-bottom'>
|
||||||
<Paper style={paperStyle} zDepth={1} rounded={false} >
|
<Paper style={paperStyle} elevation={1} >
|
||||||
<div style={{ padding: '48px 40px 36px' }}>
|
<div style={{ padding: '48px 40px 36px' }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
paddingLeft: '40px',
|
paddingLeft: '40px',
|
||||||
@@ -164,38 +175,37 @@ export class LoginComponent extends Component<ILoginComponentProps,ILoginCompone
|
|||||||
margin: 0
|
margin: 0
|
||||||
}} className='zoomOutLCorner animated'>Sign in</h2>
|
}} className='zoomOutLCorner animated'>Sign in</h2>
|
||||||
</div>
|
</div>
|
||||||
<div style={this.styles.singinOptions}>
|
<div style={this.styles.singinOptions as any}>
|
||||||
<FlatButton
|
<IconButton
|
||||||
icon={<div className='icon-fb icon'></div>}
|
onClick={() => loginWithOAuth!(OAuthType.FACEBOOK)}
|
||||||
onClick={() => loginWithOAuth(OAuthType.FACEBOOK)}
|
><div className='icon-fb icon'></div></IconButton>
|
||||||
/>
|
<IconButton
|
||||||
<FlatButton
|
onClick={() => loginWithOAuth!(OAuthType.GOOGLE)}
|
||||||
icon={<div className='icon-google icon'></div>}
|
> <div className='icon-google icon'></div> </IconButton>
|
||||||
onClick={() => loginWithOAuth(OAuthType.GOOGLE)}
|
<IconButton
|
||||||
/>
|
onClick={() => loginWithOAuth!(OAuthType.GITHUB)}
|
||||||
<FlatButton
|
> <div className='icon-github icon'></div> </IconButton>
|
||||||
icon={<div className='icon-github icon'></div>}
|
|
||||||
onClick={() => loginWithOAuth(OAuthType.GITHUB)}
|
|
||||||
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<Divider style={this.styles.divider} />
|
<Divider style={this.styles.divider} />
|
||||||
<TextField
|
<TextField
|
||||||
|
className={classes.textField}
|
||||||
|
autoFocus
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.emailInputError}
|
helperText={this.state.emailInputError}
|
||||||
|
error={this.state.emailInputError.trim() !== ''}
|
||||||
name='emailInput'
|
name='emailInput'
|
||||||
floatingLabelStyle={{ fontSize: '15px' }}
|
label='Email'
|
||||||
floatingLabelText='Email'
|
|
||||||
type='email'
|
type='email'
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
/><br />
|
/><br />
|
||||||
<TextField
|
<TextField
|
||||||
|
className={classes.textField}
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.passwordInputError}
|
helperText={this.state.passwordInputError}
|
||||||
|
error={this.state.passwordInputError.trim() !== ''}
|
||||||
name='passwordInput'
|
name='passwordInput'
|
||||||
floatingLabelStyle={{ fontSize: '15px' }}
|
label='Password'
|
||||||
floatingLabelText='Password'
|
|
||||||
type='password'
|
type='password'
|
||||||
tabIndex={2}
|
tabIndex={2}
|
||||||
/><br />
|
/><br />
|
||||||
@@ -203,10 +213,10 @@ export class LoginComponent extends Component<ILoginComponentProps,ILoginCompone
|
|||||||
<br />
|
<br />
|
||||||
<div className='login__button-box'>
|
<div className='login__button-box'>
|
||||||
<div>
|
<div>
|
||||||
<FlatButton label='Create an account' onClick={this.props.signupPage} tabIndex={4} />
|
<Button onClick={this.props.signupPage} tabIndex={4}> Create an account </Button>
|
||||||
</div>
|
</div>
|
||||||
<div >
|
<div >
|
||||||
<RaisedButton label='Login' primary={true} onClick={this.handleForm} tabIndex={3} />
|
<Button raised color='primary' onClick={this.handleForm} tabIndex={3} > Login </Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span style={this.styles.restPassword as any}>Have you forgot your password? <NavLink to='/resetPassword' style={this.styles.restPasswordLink}>reset your password</NavLink></span>
|
<span style={this.styles.restPassword as any}>Have you forgot your password? <NavLink to='/resetPassword' style={this.styles.restPasswordLink}>reset your password</NavLink></span>
|
||||||
@@ -249,4 +259,4 @@ const mapStateToProps = (state: any, ownProps: ILoginComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(LoginComponent as any))
|
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(LoginComponent as any) as any))
|
||||||
|
|||||||
@@ -109,4 +109,9 @@ export interface IMasterComponentProps {
|
|||||||
*/
|
*/
|
||||||
hideMasterLoading?: () => any
|
hideMasterLoading?: () => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether send feesback box is visible
|
||||||
|
*/
|
||||||
|
sendFeedbackStatus?: boolean
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/// <reference types="@types/material-ui" />
|
|
||||||
// - Import react components
|
// - Import react components
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { Route, Switch, NavLink, withRouter, Redirect } from 'react-router-dom'
|
import { Route, Switch, NavLink, withRouter, Redirect } from 'react-router-dom'
|
||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import Snackbar from 'material-ui/Snackbar'
|
import Snackbar from 'material-ui/Snackbar'
|
||||||
import LinearProgress from 'material-ui/LinearProgress'
|
import { LinearProgress } from 'material-ui/Progress'
|
||||||
|
|
||||||
// - Import components
|
// - Import components
|
||||||
|
|
||||||
@@ -125,12 +125,12 @@ export class MasterComponent extends Component<IMasterComponentProps, IMasterCom
|
|||||||
*/
|
*/
|
||||||
public render () {
|
public render () {
|
||||||
|
|
||||||
const { progress, global, loaded, guest, uid } = this.props
|
const { progress, global, loaded, guest, uid, sendFeedbackStatus } = this.props
|
||||||
const { loading, isVerifide } = this.state
|
const { loading, isVerifide } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id='master'>
|
<div id='master'>
|
||||||
<SendFeedback />
|
{sendFeedbackStatus ? <SendFeedback /> : ''}
|
||||||
<div className='master__progress' style={{ display: (progress.visible ? 'block' : 'none') }}>
|
<div className='master__progress' style={{ display: (progress.visible ? 'block' : 'none') }}>
|
||||||
<LinearProgress mode='determinate' value={progress.percent} />
|
<LinearProgress mode='determinate' value={progress.percent} />
|
||||||
</div>
|
</div>
|
||||||
@@ -196,7 +196,9 @@ const mapDispatchToProps = (dispatch: any, ownProps: IMasterComponentProps) => {
|
|||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any) => {
|
const mapStateToProps = (state: any) => {
|
||||||
const { authorize, global, user, post, comment, imageGallery, vote, notify, circle } = state
|
const { authorize, global, user, post, comment, imageGallery, vote, notify, circle } = state
|
||||||
|
const { sendFeedbackStatus } = global
|
||||||
return {
|
return {
|
||||||
|
sendFeedbackStatus,
|
||||||
guest: authorize.guest,
|
guest: authorize.guest,
|
||||||
uid: authorize.uid,
|
uid: authorize.uid,
|
||||||
authed: authorize.authed,
|
authed: authorize.authed,
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
// - Import react components
|
// - Import react components
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import CircularProgress from 'material-ui/CircularProgress'
|
import { CircularProgress } from 'material-ui/Progress'
|
||||||
import Dialog from 'material-ui/Dialog'
|
import Dialog from 'material-ui/Dialog'
|
||||||
import RefreshIndicator from 'material-ui/RefreshIndicator'
|
|
||||||
import { IMasterLoadingComponentProps } from './IMasterLoadingComponentProps'
|
import { IMasterLoadingComponentProps } from './IMasterLoadingComponentProps'
|
||||||
import { IMasterLoadingComponentState } from './IMasterLoadingComponentState'
|
import { IMasterLoadingComponentState } from './IMasterLoadingComponentState'
|
||||||
|
|
||||||
@@ -24,16 +23,16 @@ export default class MasterLoadingComponent extends Component<IMasterLoadingComp
|
|||||||
return (
|
return (
|
||||||
|
|
||||||
<div className='mLoading__loading' style={{ display: (activeLoading ? 'flex' : 'none') }}>
|
<div className='mLoading__loading' style={{ display: (activeLoading ? 'flex' : 'none') }}>
|
||||||
<RefreshIndicator
|
<CircularProgress
|
||||||
size={50}
|
color='secondary'
|
||||||
left={70}
|
size={50}
|
||||||
top={0}
|
mode='determinate'
|
||||||
status='loading'
|
value={25}
|
||||||
/>
|
min={0}
|
||||||
|
max={50}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ export interface INotifyComponentProps {
|
|||||||
* @type {*}
|
* @type {*}
|
||||||
* @memberof INotifyComponentProps
|
* @memberof INotifyComponentProps
|
||||||
*/
|
*/
|
||||||
anchorEl: any
|
anchorEl?: any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Material ui styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,14 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import Popover, { PopoverAnimationVertical } from 'material-ui/Popover'
|
import classNames from 'classnames'
|
||||||
|
import { Manager, Target, Popper } from 'react-popper'
|
||||||
|
import ClickAwayListener from 'material-ui/utils/ClickAwayListener'
|
||||||
|
import Grow from 'material-ui/transitions/Grow'
|
||||||
|
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 app components
|
// - Import app components
|
||||||
import NotifyItem from 'components/notifyItem'
|
import NotifyItem from 'components/notifyItem'
|
||||||
@@ -15,10 +22,30 @@ import { INotifyComponentProps } from './INotifyComponentProps'
|
|||||||
import { INotifyComponentState } from './INotifyComponentState'
|
import { INotifyComponentState } from './INotifyComponentState'
|
||||||
import { Notification } from 'core/domain/notifications'
|
import { Notification } from 'core/domain/notifications'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
root: {
|
||||||
|
width: 360,
|
||||||
|
maxWidth: 360,
|
||||||
|
backgroundColor: '#efefef',
|
||||||
|
minHeight: 376,
|
||||||
|
display: 'flex'
|
||||||
|
},
|
||||||
|
noNotify: {
|
||||||
|
color: '#888888',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
popperClose: {
|
||||||
|
pointerEvents: 'none'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*/
|
*/
|
||||||
export class NotifyComponent extends Component<INotifyComponentProps,INotifyComponentState> {
|
export class NotifyComponent extends Component<INotifyComponentProps, INotifyComponentState> {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +87,7 @@ export class NotifyComponent extends Component<INotifyComponentProps,INotifyComp
|
|||||||
let parsedDOM: any[] = []
|
let parsedDOM: any[] = []
|
||||||
if (notifications) {
|
if (notifications) {
|
||||||
Object.keys(notifications).forEach((key) => {
|
Object.keys(notifications).forEach((key) => {
|
||||||
const {notifierUserId} = notifications![key]
|
const { notifierUserId } = notifications![key]
|
||||||
parsedDOM.push(
|
parsedDOM.push(
|
||||||
<NotifyItem
|
<NotifyItem
|
||||||
key={key}
|
key={key}
|
||||||
@@ -68,7 +95,7 @@ export class NotifyComponent extends Component<INotifyComponentProps,INotifyComp
|
|||||||
fullName={(info![notifierUserId] ? info![notifierUserId].fullName || '' : '')}
|
fullName={(info![notifierUserId] ? info![notifierUserId].fullName || '' : '')}
|
||||||
avatar={(info![notifierUserId] ? info![notifierUserId].avatar || '' : '')}
|
avatar={(info![notifierUserId] ? info![notifierUserId].avatar || '' : '')}
|
||||||
id={key}
|
id={key}
|
||||||
isSeen={(notifications![key] ? notifications![key].isSeen || false : false )}
|
isSeen={(notifications![key] ? notifications![key].isSeen || false : false)}
|
||||||
url={(notifications![key] ? notifications![key].url || '' : '')}
|
url={(notifications![key] ? notifications![key].url || '' : '')}
|
||||||
notifierUserId={notifierUserId}
|
notifierUserId={notifierUserId}
|
||||||
closeNotify={onRequestClose}
|
closeNotify={onRequestClose}
|
||||||
@@ -84,25 +111,27 @@ export class NotifyComponent extends Component<INotifyComponentProps,INotifyComp
|
|||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
let { open, anchorEl, onRequestClose } = this.props
|
let { open, anchorEl, onRequestClose, classes } = this.props
|
||||||
|
const noNotify = ( <div className={classes.noNotify}>
|
||||||
|
All caught up! </div>)
|
||||||
|
const items = this.notifyItemList()
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popper
|
||||||
className='homeHeader__notify-menu'
|
placement='bottom-start'
|
||||||
open={open}
|
eventsEnabled={open}
|
||||||
anchorEl={anchorEl}
|
className={classNames({ [classes.popperClose]: !open })}
|
||||||
anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}
|
|
||||||
targetOrigin={{ horizontal: 'left', vertical: 'top' }}
|
|
||||||
onRequestClose={onRequestClose}
|
|
||||||
>
|
>
|
||||||
<div className='container'>
|
|
||||||
<div className='title'>Green </div>
|
|
||||||
<div className='content'>
|
|
||||||
{this.notifyItemList()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Popover>
|
|
||||||
|
|
||||||
|
<ClickAwayListener onClickAway={onRequestClose}>
|
||||||
|
<Grow in={open} style={{ transformOrigin: '0 0 0' }}>
|
||||||
|
<Paper className={classes.root} elevation={4} >
|
||||||
|
|
||||||
|
{items.length > 0 ? <List>{items}</List> : noNotify}
|
||||||
|
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Popper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,4 +162,4 @@ const mapStateToProps = (state: any, ownProps: INotifyComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(NotifyComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(NotifyComponent as any) as any)
|
||||||
|
|||||||
@@ -83,4 +83,9 @@ export interface INotifyItemComponentProps {
|
|||||||
* @memberof INotifyItemComponentProps
|
* @memberof INotifyItemComponentProps
|
||||||
*/
|
*/
|
||||||
seenNotify?: (notificationId: string) => any
|
seenNotify?: (notificationId: string) => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Material ui styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import PropTypes from 'prop-types'
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink } from 'react-router-dom'
|
||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import SvgClose from 'material-ui/svg-icons/navigation/close'
|
import SvgClose from 'material-ui-icons/close'
|
||||||
import { grey400 } from 'material-ui/styles/colors'
|
import { grey } from 'material-ui/colors'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
import List, { ListItem, ListItemSecondaryAction, ListItemText } from 'material-ui/List'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import UserAvatar from 'components/userAvatar'
|
import UserAvatar from 'components/userAvatar'
|
||||||
@@ -18,6 +20,20 @@ import * as notifyActions from 'actions/notifyActions'
|
|||||||
import { INotifyItemComponentProps } from './INotifyItemComponentProps'
|
import { INotifyItemComponentProps } from './INotifyItemComponentProps'
|
||||||
import { INotifyItemComponentState } from './INotifyItemComponentState'
|
import { INotifyItemComponentState } from './INotifyItemComponentState'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
root: {
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: 360,
|
||||||
|
backgroundColor: theme.palette.background.paper
|
||||||
|
},
|
||||||
|
closeButton: {color: 'black'},
|
||||||
|
closeIcon: {width: 12, height: 12},
|
||||||
|
listItem: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
marginBottom: '6px'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*/
|
*/
|
||||||
@@ -90,13 +106,12 @@ export class NotifyItemComponent extends Component<INotifyItemComponentProps,INo
|
|||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
let { description, fullName, avatar, isSeen, id, goTo,closeNotify, notifierUserId, url, deleteNotiy } = this.props
|
let { description, fullName, avatar, isSeen, id, goTo,closeNotify, notifierUserId, url, deleteNotiy, classes } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<div className='item' style={isSeen ? { opacity: 0.6 } : {}} key={id}>
|
<ListItem key={notifierUserId} dense button className={classes.listItem} style={isSeen ? { opacity: 0.6 } : {}}>
|
||||||
<div className='avatar'>
|
<NavLink
|
||||||
<NavLink
|
|
||||||
to={`/${notifierUserId}`}
|
to={`/${notifierUserId}`}
|
||||||
onClick={(evt) => {
|
onClick={(evt) => {
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
@@ -106,21 +121,20 @@ export class NotifyItemComponent extends Component<INotifyItemComponentProps,INo
|
|||||||
>
|
>
|
||||||
<UserAvatar fullName={fullName} fileName={avatar} />
|
<UserAvatar fullName={fullName} fileName={avatar} />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
<ListItemText primary={<NavLink to={url} onClick={this.handleSeenNotify}>
|
||||||
<div className='info'>
|
|
||||||
<NavLink to={url} onClick={this.handleSeenNotify}>
|
|
||||||
<div className='user-name'>
|
<div className='user-name'>
|
||||||
{fullName}
|
{fullName}
|
||||||
</div>
|
</div>
|
||||||
<div className='description'>
|
<div className='description'>
|
||||||
{description}
|
{description}
|
||||||
</div>
|
</div>
|
||||||
</NavLink>
|
</NavLink>} />
|
||||||
|
<ListItemSecondaryAction className={classes.closeButton}>
|
||||||
|
<div onClick={() => deleteNotiy!(id)}>
|
||||||
|
<SvgClose className={classes.closeIcon} style={{ cursor: 'pointer' }} />
|
||||||
</div>
|
</div>
|
||||||
<div className='close' onClick={() => deleteNotiy!(id)}>
|
</ListItemSecondaryAction>
|
||||||
<SvgClose hoverColor={grey400} style={{ cursor: 'pointer' }} />
|
</ListItem>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -153,4 +167,4 @@ const mapStateToProps = (state: any, ownProps: INotifyItemComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(NotifyItemComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(NotifyItemComponent as any) as any )
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
|
|
||||||
export interface IPeopleComponentState {
|
export interface IPeopleComponentState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tab index
|
||||||
|
*/
|
||||||
|
tabIndex: number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ import React, { Component } from 'react'
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { withRouter } from 'react-router-dom'
|
import { withRouter } from 'react-router-dom'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Tabs, Tab } from 'material-ui/Tabs'
|
import Tabs, { Tab } from 'material-ui/Tabs'
|
||||||
import { grey50, grey200, grey400, grey600, cyan500 } from 'material-ui/styles/colors'
|
import { grey, cyan } from 'material-ui/colors'
|
||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
|
import AppBar from 'material-ui/AppBar'
|
||||||
|
import Typography from 'material-ui/Typography'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import FindPeople from 'components/findPeople'
|
import FindPeople from 'components/findPeople'
|
||||||
@@ -21,6 +23,14 @@ import * as globalActions from 'actions/globalActions'
|
|||||||
import { IPeopleComponentProps } from './IPeopleComponentProps'
|
import { IPeopleComponentProps } from './IPeopleComponentProps'
|
||||||
import { IPeopleComponentState } from './IPeopleComponentState'
|
import { IPeopleComponentState } from './IPeopleComponentState'
|
||||||
|
|
||||||
|
const TabContainer = (props: any) => {
|
||||||
|
return (
|
||||||
|
<Typography component='div' style={{ padding: 8 * 3 }}>
|
||||||
|
{props.children}
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*/
|
*/
|
||||||
@@ -36,16 +46,41 @@ export class PeopleComponent extends Component<IPeopleComponentProps,IPeopleComp
|
|||||||
*/
|
*/
|
||||||
constructor (props: IPeopleComponentProps) {
|
constructor (props: IPeopleComponentProps) {
|
||||||
super(props)
|
super(props)
|
||||||
|
const {tab} = this.props.match.params
|
||||||
// Defaul state
|
// Defaul state
|
||||||
this.state = {
|
this.state = {
|
||||||
|
tabIndex: this.getTabIndexByNav(tab)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binding functions to `this`
|
// Binding functions to `this`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hadle on tab change
|
||||||
|
*/
|
||||||
|
handleChangeTab = (event: any, value: any) => {
|
||||||
|
const {circlesLoaded, goTo, setHeaderTitle} = this.props
|
||||||
|
this.setState({ tabIndex: value })
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
goTo!('/people')
|
||||||
|
setHeaderTitle!('People')
|
||||||
|
break
|
||||||
|
case 1:
|
||||||
|
goTo!('/people/circles')
|
||||||
|
setHeaderTitle!('Circles')
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
goTo!('/people/followers')
|
||||||
|
setHeaderTitle!('Followers')
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentWillMount () {
|
componentWillMount () {
|
||||||
const { setHeaderTitle} = this.props
|
const { setHeaderTitle} = this.props
|
||||||
const {tab} = this.props.match.params
|
const {tab} = this.props.match.params
|
||||||
@@ -91,48 +126,44 @@ export class PeopleComponent extends Component<IPeopleComponentProps,IPeopleComp
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {circlesLoaded, goTo, setHeaderTitle} = this.props
|
const {circlesLoaded, goTo, setHeaderTitle} = this.props
|
||||||
const {tab} = this.props.match.params
|
const {tabIndex} = this.state
|
||||||
let tabIndex = 0
|
|
||||||
switch (tab) {
|
|
||||||
case undefined:
|
|
||||||
case '':
|
|
||||||
tabIndex = 0
|
|
||||||
break
|
|
||||||
case 'circles':
|
|
||||||
tabIndex = 1
|
|
||||||
break
|
|
||||||
case 'followers':
|
|
||||||
tabIndex = 2
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<div style={styles.people}>
|
<div style={styles.people}>
|
||||||
<Tabs inkBarStyle={{backgroundColor: grey50}} initialSelectedIndex={tabIndex} >
|
<AppBar position='static' color='default'>
|
||||||
<Tab label='Find People' onActive={() => {
|
<Tabs indicatorColor= {grey[50]}
|
||||||
goTo!('/people')
|
onChange={this.handleChangeTab}
|
||||||
setHeaderTitle!('People')
|
value={tabIndex} centered
|
||||||
}} >
|
textColor='primary'
|
||||||
{circlesLoaded ? <FindPeople /> : ''}
|
>
|
||||||
</Tab>
|
<Tab label='Find People' />
|
||||||
<Tab label='Following' onActive={() => {
|
<Tab label='Following' />
|
||||||
goTo!('/people/circles')
|
<Tab label='Followers' />
|
||||||
setHeaderTitle!('Circles')
|
|
||||||
}} >
|
|
||||||
{circlesLoaded ? <Following/> : ''}
|
|
||||||
{circlesLoaded ? <YourCircles/> : ''}
|
|
||||||
</Tab>
|
|
||||||
<Tab label='Followers' onActive={() => {
|
|
||||||
goTo!('/people/followers')
|
|
||||||
setHeaderTitle!('Followers')
|
|
||||||
}}>
|
|
||||||
{circlesLoaded ? <Followers /> : ''}
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
</AppBar>
|
||||||
|
{tabIndex === 0 && <TabContainer>{circlesLoaded ? <FindPeople /> : ''}</TabContainer>}
|
||||||
|
{tabIndex === 1 && <TabContainer>
|
||||||
|
{circlesLoaded ? <Following/> : ''}
|
||||||
|
{circlesLoaded ? <YourCircles/> : ''}
|
||||||
|
</TabContainer>}
|
||||||
|
{tabIndex === 2 && <TabContainer>{circlesLoaded ? <Followers /> : ''}</TabContainer>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get tab index by navigation name
|
||||||
|
*/
|
||||||
|
private getTabIndexByNav: (navName: string) => number = (navName: string) => {
|
||||||
|
let tabIndex = 0
|
||||||
|
switch (navName) {
|
||||||
|
case 'circles':
|
||||||
|
return 1
|
||||||
|
case 'followers':
|
||||||
|
return 2
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -114,4 +114,9 @@ export interface IPostComponentProps {
|
|||||||
* @memberof ICommentGroupComponentProps
|
* @memberof ICommentGroupComponentProps
|
||||||
*/
|
*/
|
||||||
commentList?: {[commentId: string]: Comment}
|
commentList?: {[commentId: string]: Comment}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,5 +38,18 @@ export interface IPostComponentState {
|
|||||||
*/
|
*/
|
||||||
openPostWrite: boolean
|
openPostWrite: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the comment group
|
||||||
|
*/
|
||||||
openCommentGroup?: () => void
|
openCommentGroup?: () => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post menu anchor element
|
||||||
|
*/
|
||||||
|
postMenuAnchorEl?: any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether post menu open
|
||||||
|
*/
|
||||||
|
isPostMenuOpen?: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,27 +6,33 @@ import { push } from 'react-router-redux'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import Linkify from 'react-linkify'
|
import Linkify from 'react-linkify'
|
||||||
|
import copy from 'copy-to-clipboard'
|
||||||
|
|
||||||
// - Material UI
|
// - Material UI
|
||||||
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card'
|
import { Card, CardActions, CardHeader, CardMedia, CardContent } from 'material-ui'
|
||||||
import FloatingActionButton from 'material-ui/FloatingActionButton'
|
import Typography from 'material-ui/Typography'
|
||||||
import SvgShare from 'material-ui/svg-icons/social/share'
|
import SvgShare from 'material-ui-icons/share'
|
||||||
import SvgLink from 'material-ui/svg-icons/content/link'
|
import SvgLink from 'material-ui-icons/link'
|
||||||
import SvgComment from 'material-ui/svg-icons/communication/comment'
|
import SvgComment from 'material-ui-icons/comment'
|
||||||
import SvgFavorite from 'material-ui/svg-icons/action/favorite'
|
import SvgFavorite from 'material-ui-icons/favorite'
|
||||||
import SvgFavoriteBorder from 'material-ui/svg-icons/action/favorite-border'
|
import SvgFavoriteBorder from 'material-ui-icons/favoriteBorder'
|
||||||
import Checkbox from 'material-ui/Checkbox'
|
import Checkbox from 'material-ui/Checkbox'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import Divider from 'material-ui/Divider'
|
import Divider from 'material-ui/Divider'
|
||||||
import { grey200, grey400, grey600 } from 'material-ui/styles/colors'
|
import { grey } from 'material-ui/colors'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import Menu from 'material-ui/Menu'
|
import Menu from 'material-ui/Menu'
|
||||||
import MenuItem from 'material-ui/MenuItem'
|
import { MenuList, MenuItem } from 'material-ui/Menu'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import Dialog from 'material-ui/Dialog'
|
import Dialog from 'material-ui/Dialog'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'
|
import MoreVertIcon from 'material-ui-icons/moreVert'
|
||||||
import IconMenu from 'material-ui/IconMenu'
|
import { ListItemIcon, ListItemText } from 'material-ui/List'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
import { Manager, Target, Popper } from 'react-popper'
|
||||||
|
import Grow from 'material-ui/transitions/Grow'
|
||||||
|
import ClickAwayListener from 'material-ui/utils/ClickAwayListener'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import reactStringReplace from 'react-string-replace'
|
import reactStringReplace from 'react-string-replace'
|
||||||
|
|
||||||
@@ -45,33 +51,68 @@ import * as globalActions from 'actions/globalActions'
|
|||||||
import { IPostComponentProps } from './IPostComponentProps'
|
import { IPostComponentProps } from './IPostComponentProps'
|
||||||
import { IPostComponentState } from './IPostComponentState'
|
import { IPostComponentState } from './IPostComponentState'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
iconButton: {
|
||||||
|
width: 27,
|
||||||
|
marginLeft: 5
|
||||||
|
},
|
||||||
|
vote: {
|
||||||
|
display: 'flex',
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
voteCounter: {
|
||||||
|
color: 'rgb(134, 129, 129)',
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: 100,
|
||||||
|
padding: 2
|
||||||
|
},
|
||||||
|
commentCounter: {
|
||||||
|
color: 'rgb(134, 129, 129)',
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: 100,
|
||||||
|
padding: 4
|
||||||
|
},
|
||||||
|
popperOpen: {
|
||||||
|
zIndex: 10
|
||||||
|
},
|
||||||
|
popperClose: {
|
||||||
|
pointerEvents: 'none',
|
||||||
|
zIndex: 0
|
||||||
|
},
|
||||||
|
shareLinkPaper: {
|
||||||
|
minHeight: 80,
|
||||||
|
padding: 10,
|
||||||
|
minWidth: 460
|
||||||
|
},
|
||||||
|
clipboard: {
|
||||||
|
fontSize: '18px',
|
||||||
|
textAlign: 'center',
|
||||||
|
marginTop: '10px',
|
||||||
|
color: '#1e882d',
|
||||||
|
fontWeight: 100
|
||||||
|
},
|
||||||
|
postBody: {
|
||||||
|
wordWrap: 'break-word',
|
||||||
|
color: 'rgba(0, 0, 0, 0.87)',
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
fontWeight: 400,
|
||||||
|
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
||||||
|
lineHeight: '1.46429em'
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
width: '100%',
|
||||||
|
height: 500
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// - Create component class
|
// - Create component class
|
||||||
export class PostComponent extends Component<IPostComponentProps,IPostComponentState> {
|
export class PostComponent extends Component<IPostComponentProps, IPostComponentState> {
|
||||||
|
|
||||||
styles = {
|
styles = {
|
||||||
counter: {
|
|
||||||
lineHeight: '36px',
|
|
||||||
color: '#777',
|
|
||||||
fontSize: '12px',
|
|
||||||
marginRight: '6px'
|
|
||||||
},
|
|
||||||
postBody: {
|
|
||||||
wordWrap: 'break-word'
|
|
||||||
},
|
|
||||||
dialog: {
|
dialog: {
|
||||||
width: '',
|
width: '',
|
||||||
maxWidth: '530px',
|
maxWidth: '530px',
|
||||||
borderRadius: '4px'
|
borderRadius: '4px'
|
||||||
},
|
|
||||||
rightIconMenu: {
|
|
||||||
position: 'absolute',
|
|
||||||
right: 18,
|
|
||||||
top: 8
|
|
||||||
},
|
|
||||||
iconButton: {
|
|
||||||
width: 24,
|
|
||||||
height: 24
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -82,7 +123,7 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
|||||||
*/
|
*/
|
||||||
constructor (props: IPostComponentProps) {
|
constructor (props: IPostComponentProps) {
|
||||||
super(props)
|
super(props)
|
||||||
const {post} = props
|
const { post } = props
|
||||||
this.state = {
|
this.state = {
|
||||||
/**
|
/**
|
||||||
* Post text
|
* Post text
|
||||||
@@ -119,7 +160,15 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
|||||||
/**
|
/**
|
||||||
* If it's true, post write will be open
|
* If it's true, post write will be open
|
||||||
*/
|
*/
|
||||||
openPostWrite: false
|
openPostWrite: false,
|
||||||
|
/**
|
||||||
|
* Post menu anchor element
|
||||||
|
*/
|
||||||
|
postMenuAnchorEl: null,
|
||||||
|
/**
|
||||||
|
* Whether post menu open
|
||||||
|
*/
|
||||||
|
isPostMenuOpen: false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binding functions to this
|
// Binding functions to this
|
||||||
@@ -140,10 +189,10 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
|||||||
* @param {event} evt passed by clicking on comment slide show
|
* @param {event} evt passed by clicking on comment slide show
|
||||||
*/
|
*/
|
||||||
handleOpenComments = () => {
|
handleOpenComments = () => {
|
||||||
const { getPostComments, commentList, post} = this.props
|
const { getPostComments, commentList, post } = this.props
|
||||||
const {id, ownerUserId} = post
|
const { id, ownerUserId } = post
|
||||||
if (!commentList) {
|
if (!commentList) {
|
||||||
getPostComments(ownerUserId!, id!)
|
getPostComments!(ownerUserId!, id!)
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
openComments: !this.state.openComments
|
openComments: !this.state.openComments
|
||||||
@@ -181,10 +230,31 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
|||||||
* @memberof Post
|
* @memberof Post
|
||||||
*/
|
*/
|
||||||
handleDelete = () => {
|
handleDelete = () => {
|
||||||
const {post} = this.props
|
const { post } = this.props
|
||||||
this.props.delete!(post.id!)
|
this.props.delete!(post.id!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open post menu
|
||||||
|
*/
|
||||||
|
openPostMenu = (event: any) => {
|
||||||
|
console.log(event.currentTarget)
|
||||||
|
this.setState({
|
||||||
|
postMenuAnchorEl: event.currentTarget,
|
||||||
|
isPostMenuOpen: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close post menu
|
||||||
|
*/
|
||||||
|
closePostMenu = (event: any) => {
|
||||||
|
this.setState({
|
||||||
|
postMenuAnchorEl: event.currentTarget,
|
||||||
|
isPostMenuOpen: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show copy link
|
* Show copy link
|
||||||
*
|
*
|
||||||
@@ -205,6 +275,8 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
|||||||
* @memberof Post
|
* @memberof Post
|
||||||
*/
|
*/
|
||||||
handleOpenShare = () => {
|
handleOpenShare = () => {
|
||||||
|
const {post} = this.props
|
||||||
|
copy(`${location.origin}/${post.ownerUserId}/posts/${post.id}`)
|
||||||
this.setState({
|
this.setState({
|
||||||
shareOpen: true
|
shareOpen: true
|
||||||
})
|
})
|
||||||
@@ -264,77 +336,114 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
|||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
const {post ,setHomeTitle, goTo, fullName, isPostOwner, commentList, avatar} = this.props
|
const { post, setHomeTitle, goTo, fullName, isPostOwner, commentList, avatar, classes } = this.props
|
||||||
|
const { postMenuAnchorEl, isPostMenuOpen } = this.state
|
||||||
const RightIconMenu = () => (
|
const RightIconMenu = () => (
|
||||||
<IconMenu iconButtonElement={IconButtonElement} style={{ display: 'block', position: 'absolute', top: '0px', right: '4px' }}>
|
<Manager>
|
||||||
<MenuItem primaryText='Edit' onClick={this.handleOpenPostWrite} />
|
<Target>
|
||||||
<MenuItem primaryText='Delete' onClick={this.handleDelete} />
|
<IconButton
|
||||||
<MenuItem primaryText={post.disableComments ? 'Enable comments' : 'Disable comments'} onClick={() => this.props.toggleDisableComments!(!post.disableComments)} />
|
aria-owns={isPostMenuOpen! ? 'post-menu' : null}
|
||||||
<MenuItem primaryText={post.disableSharing ? 'Enable sharing' : 'Disable sharing'} onClick={() => this.props.toggleSharingComments!(!post.disableSharing)} />
|
aria-haspopup='true'
|
||||||
</IconMenu>
|
onClick={this.openPostMenu.bind(this)}
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
</Target>
|
||||||
|
<Popper
|
||||||
|
placement='bottom-start'
|
||||||
|
eventsEnabled={isPostMenuOpen!}
|
||||||
|
className={classNames({ [classes.popperClose]: !isPostMenuOpen! }, { [classes.popperOpen]: isPostMenuOpen! })}
|
||||||
|
>
|
||||||
|
<ClickAwayListener onClickAway={this.closePostMenu}>
|
||||||
|
<Grow in={isPostMenuOpen!} id='post-menu' style={{ transformOrigin: '0 0 0' }}>
|
||||||
|
<Paper>
|
||||||
|
<MenuList role='menu'>
|
||||||
|
<MenuItem onClick={this.handleOpenPostWrite} > Edit </MenuItem>
|
||||||
|
<MenuItem onClick={this.handleDelete} > Delete </MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => this.props.toggleDisableComments!(!post.disableComments)} >
|
||||||
|
{post.disableComments ? 'Enable comments' : 'Disable comments'}
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => this.props.toggleSharingComments!(!post.disableSharing)} >
|
||||||
|
{post.disableSharing ? 'Enable sharing' : 'Disable sharing'}
|
||||||
|
</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Popper>
|
||||||
|
</Manager>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {ownerUserId, ownerDisplayName, creationDate, image, body} = post
|
const { ownerUserId, ownerDisplayName, creationDate, image, body } = post
|
||||||
// Define variables
|
// Define variables
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader
|
<CardHeader
|
||||||
title={<NavLink to={`/${ownerUserId}`}>{ownerDisplayName}</NavLink>}
|
title={<NavLink to={`/${ownerUserId}`}>{ownerDisplayName}</NavLink>}
|
||||||
subtitle={moment.unix(creationDate!).fromNow() + ' | public'}
|
subheader={moment.unix(creationDate!).fromNow() + ' | public'}
|
||||||
avatar={<NavLink to={`/${ownerUserId}`}><UserAvatar fullName={fullName!} fileName={avatar!} size={36} /></NavLink>}
|
avatar={<NavLink to={`/${ownerUserId}`}><UserAvatar fullName={fullName!} fileName={avatar!} size={36} /></NavLink>}
|
||||||
|
action={isPostOwner ? <RightIconMenu /> : ''}
|
||||||
>
|
>
|
||||||
{isPostOwner ? ( <div style={this.styles.rightIconMenu as any}><RightIconMenu /></div>) : ''}
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
{image ? (
|
{image ? (
|
||||||
<CardMedia>
|
<CardMedia image={image}>
|
||||||
<Img fileName={image} />
|
<Img fileName={image} />
|
||||||
</CardMedia>) : ''}
|
</CardMedia>) : ''}
|
||||||
|
|
||||||
<CardText style={this.styles.postBody}>
|
<CardContent className={classes.postBody}>
|
||||||
<Linkify properties={{target: '_blank', style: {color: 'blue'}}}>
|
<Linkify properties={{ target: '_blank', style: { color: 'blue' } }}>
|
||||||
{reactStringReplace(body,/#(\w+)/g, (match: string, i: string) => (
|
{reactStringReplace(body, /#(\w+)/g, (match: string, i: string) => (
|
||||||
<NavLink
|
<NavLink
|
||||||
style={{color: 'green'}}
|
style={{ color: 'green' }}
|
||||||
key={match + i}
|
key={match + i}
|
||||||
to={`/tag/${match}`}
|
to={`/tag/${match}`}
|
||||||
onClick ={evt => {
|
onClick={evt => {
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
goTo!(`/tag/${match}`)
|
goTo!(`/tag/${match}`)
|
||||||
setHomeTitle!(`#${match}`)
|
setHomeTitle!(`#${match}`)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
#{match}
|
#{match}
|
||||||
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
))}
|
))}
|
||||||
</Linkify>
|
</Linkify>
|
||||||
</CardText>
|
</CardContent>
|
||||||
<CardActions>
|
<CardActions>
|
||||||
<div style={{ margin: '16px 8px', display: 'flex', justifyContent: 'space-between' }}>
|
<div className={classes.vote}>
|
||||||
<div style={{ display: 'flex' }}>
|
<IconButton
|
||||||
{/*<FloatingActionButton style={{ margin: "0 8px" }} zDepth={1} backgroundColor={grey200} iconStyle={{ color: grey600, fill: grey600, height: "36px", width: "36px" }} zDepth={1} secondary={false}>*/}
|
className={classes.iconButton}
|
||||||
<div className='g__circle' onClick={this.handleVote}>
|
onClick={this.handleVote}
|
||||||
|
aria-label='Love'>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checkedIcon={<SvgFavorite style={{fill: '#4CAF50'}}/>}
|
className={classes.iconButton}
|
||||||
uncheckedIcon={<SvgFavoriteBorder style={{fill: '#757575'}} />}
|
checkedIcon={<SvgFavorite style={{ fill: '#4CAF50' }} />}
|
||||||
checked={this.props.currentUserVote}
|
icon={<SvgFavoriteBorder style={{ fill: '#757575' }} />}
|
||||||
style={{transform: 'translate(6px, 6px)'}}
|
checked={this.props.currentUserVote}
|
||||||
/>
|
/>
|
||||||
</div>
|
<div className={classes.voteCounter}> {this.props.voteCount! > 0 ? this.props.voteCount : ''} </div>
|
||||||
<div style={this.styles.counter}> {this.props.voteCount! > 0 ? this.props.voteCount : ''} </div>
|
</IconButton>
|
||||||
</div>
|
|
||||||
<div style={{ display: 'flex' }}>
|
|
||||||
{!post.disableComments ? (<div style={{display: 'inherit'}}><FloatingActionButton onClick={this.handleOpenComments} style={{ margin: '0 8px' }} backgroundColor={grey200} iconStyle={{ color: grey600, fill: grey600, height: '36px', width: '36px' }} zDepth={1} secondary={false}>
|
|
||||||
<SvgComment viewBox='0 -9 24 34' style={{ height: '30px', width: '30px' }} /> 3
|
|
||||||
</FloatingActionButton>
|
|
||||||
<div style={this.styles.counter}>{post.commentCounter! > 0 ? post.commentCounter : ''} </div></div>) : ''}
|
|
||||||
{!post.disableSharing ? (<FloatingActionButton onClick={this.handleOpenShare} style={{ margin: '0 8px' }} backgroundColor={grey200} iconStyle={{ color: grey600, fill: grey600, height: '36px', width: '36px' }} zDepth={1} secondary={false}>
|
|
||||||
<SvgShare viewBox='0 -9 24 34' style={{ height: '30px', width: '30px' }} />
|
|
||||||
</FloatingActionButton>) : ''}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
{!post.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>
|
||||||
|
</IconButton>
|
||||||
|
</div>) : ''}
|
||||||
|
{!post.disableSharing ? (<IconButton
|
||||||
|
className={classes.iconButton}
|
||||||
|
onClick={this.handleOpenShare}
|
||||||
|
aria-label='Comment'>
|
||||||
|
<SvgShare />
|
||||||
|
</IconButton>) : ''}
|
||||||
|
|
||||||
</CardActions>
|
</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={post.ownerUserId!} onToggleRequest={this.handleOpenComments} isPostOwner={this.props.isPostOwner!} disableComments={post.disableComments!} postId={post.id!} />
|
||||||
@@ -342,29 +451,33 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
|||||||
{/* Copy link dialog*/}
|
{/* Copy link dialog*/}
|
||||||
<Dialog
|
<Dialog
|
||||||
title='Share On'
|
title='Share On'
|
||||||
modal={false}
|
|
||||||
open={this.state.shareOpen}
|
open={this.state.shareOpen}
|
||||||
onRequestClose={this.handleCloseShare}
|
onClose={this.handleCloseShare}
|
||||||
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
|
|
||||||
contentStyle={this.styles.dialog}
|
|
||||||
autoDetectWindowHeight={false}
|
|
||||||
actionsContainerStyle={{ borderTop: '1px solid rgb(224, 224, 224)' }}
|
|
||||||
>
|
>
|
||||||
{!this.state.openCopyLink
|
<Paper className={classes.shareLinkPaper}>
|
||||||
? (<Paper >
|
{!this.state.openCopyLink
|
||||||
<Menu>
|
? (<MenuList>
|
||||||
<MenuItem primaryText='Copy Link' leftIcon={<SvgLink />} onClick={this.handleCopyLink} />
|
<MenuItem onClick={this.handleCopyLink} >
|
||||||
</Menu>
|
<ListItemIcon>
|
||||||
</Paper>)
|
<SvgLink />
|
||||||
: <TextField fullWidth={true} id='text-field-default' defaultValue={`${location.origin}/${post.ownerUserId}/posts/${post.id}`} />
|
</ListItemIcon>
|
||||||
}
|
<ListItemText inset primary='Copy Link' />
|
||||||
|
</MenuItem>
|
||||||
|
</MenuList>)
|
||||||
|
: <div>
|
||||||
|
<TextField autoFocus fullWidth={true} id='text-field-default' defaultValue={`${location.origin}/${post.ownerUserId}/posts/${post.id}`} />
|
||||||
|
<Typography className={classNames('animate-top', classes.clipboard)} type='headline' component='h2'>
|
||||||
|
Link has been copied to clipboard ...
|
||||||
|
</Typography>
|
||||||
|
</div>}
|
||||||
|
</Paper>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<PostWrite
|
<PostWrite
|
||||||
open={this.state.openPostWrite}
|
open={this.state.openPostWrite}
|
||||||
onRequestClose={this.handleClosePostWrite}
|
onRequestClose={this.handleClosePostWrite}
|
||||||
edit={true}
|
edit={true}
|
||||||
postModel= {post}
|
postModel={post}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</Card>
|
</Card>
|
||||||
@@ -380,10 +493,10 @@ export class PostComponent extends Component<IPostComponentProps,IPostComponentS
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapDispatchToProps = (dispatch: any, ownProps: IPostComponentProps) => {
|
const mapDispatchToProps = (dispatch: any, ownProps: IPostComponentProps) => {
|
||||||
const {post} = ownProps
|
const { post } = ownProps
|
||||||
return {
|
return {
|
||||||
vote: () => dispatch(voteActions.dbAddVote(post.id!,post.ownerUserId!)),
|
vote: () => dispatch(voteActions.dbAddVote(post.id!, post.ownerUserId!)),
|
||||||
unvote: () => dispatch(voteActions.dbDeleteVote(post.id!, post.ownerUserId!)) ,
|
unvote: () => dispatch(voteActions.dbDeleteVote(post.id!, post.ownerUserId!)),
|
||||||
delete: (id: string) => dispatch(postActions.dbDeletePost(id)),
|
delete: (id: string) => dispatch(postActions.dbDeletePost(id)),
|
||||||
toggleDisableComments: (status: boolean) => {
|
toggleDisableComments: (status: boolean) => {
|
||||||
post.disableComments = status
|
post.disableComments = status
|
||||||
@@ -391,11 +504,11 @@ const mapDispatchToProps = (dispatch: any, ownProps: IPostComponentProps) => {
|
|||||||
},
|
},
|
||||||
toggleSharingComments: (status: boolean) => {
|
toggleSharingComments: (status: boolean) => {
|
||||||
post.disableSharing = status
|
post.disableSharing = status
|
||||||
dispatch(postActions.dbUpdatePost({id: post.id!, disableSharing: status},(x: any) => x))
|
dispatch(postActions.dbUpdatePost({ id: post.id!, disableSharing: status }, (x: any) => x))
|
||||||
},
|
},
|
||||||
goTo: (url: string) => dispatch(push(url)),
|
goTo: (url: string) => dispatch(push(url)),
|
||||||
setHomeTitle: (title: string) => dispatch(globalActions.setHeaderTitle(title || '')),
|
setHomeTitle: (title: string) => dispatch(globalActions.setHeaderTitle(title || '')),
|
||||||
getPostComments: (ownerUserId: string, postId: string) => dispatch(commentActions.dbGetComments(ownerUserId,postId))
|
getPostComments: (ownerUserId: string, postId: string) => dispatch(commentActions.dbGetComments(ownerUserId, postId))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,13 +520,12 @@ const mapDispatchToProps = (dispatch: any, ownProps: IPostComponentProps) => {
|
|||||||
* @return {object} props of component
|
* @return {object} props of component
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = (state: any, ownProps: IPostComponentProps) => {
|
const mapStateToProps = (state: any, ownProps: IPostComponentProps) => {
|
||||||
const {post, vote, authorize, comment} = state
|
const { post, vote, authorize, comment } = state
|
||||||
const {uid} = authorize
|
const { uid } = authorize
|
||||||
let currentUserVote = ownProps.post.votes ? ownProps.post.votes[uid] : false
|
let currentUserVote = ownProps.post.votes ? ownProps.post.votes[uid] : false
|
||||||
const postModel = post.userPosts[ownProps.post.ownerUserId!][ownProps.post.id!]
|
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 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 commentList: { [commentId: string]: Comment } = comment.postComments[ownProps.post.id!]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
commentList,
|
commentList,
|
||||||
avatar: state.user.info && state.user.info[ownProps.post.ownerUserId!] ? state.user.info[ownProps.post.ownerUserId!].avatar || '' : '',
|
avatar: state.user.info && state.user.info[ownProps.post.ownerUserId!] ? state.user.info[ownProps.post.ownerUserId!].avatar || '' : '',
|
||||||
@@ -425,4 +537,4 @@ const mapStateToProps = (state: any, ownProps: IPostComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(PostComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(PostComponent as any) as any)
|
||||||
|
|||||||
@@ -70,4 +70,9 @@ export interface IPostWriteComponentProps {
|
|||||||
* @memberof IPostWriteComponentProps
|
* @memberof IPostWriteComponentProps
|
||||||
*/
|
*/
|
||||||
update?: (post: Post, callback: Function) => any
|
update?: (post: Post, callback: Function) => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ export interface IPostWriteComponentState {
|
|||||||
/**
|
/**
|
||||||
* If it's true share will be disabled on post
|
* If it's true share will be disabled on post
|
||||||
*/
|
*/
|
||||||
disableSharing: boolean
|
disableSharing: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether menu is open
|
||||||
|
*/
|
||||||
|
menuOpen: boolean
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,37 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { List, ListItem } from 'material-ui/List'
|
|
||||||
|
import { Card, CardActions, CardHeader, CardMedia, CardContent } from 'material-ui'
|
||||||
|
import List, {
|
||||||
|
ListItem,
|
||||||
|
ListItemAvatar,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemSecondaryAction,
|
||||||
|
ListItemText
|
||||||
|
} from 'material-ui/List'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import Dialog from 'material-ui/Dialog'
|
import Dialog, {
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
DialogActions,
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
DialogContent,
|
||||||
import { grey400, grey800, darkBlack, lightBlack } from 'material-ui/styles/colors'
|
DialogContentText,
|
||||||
|
DialogTitle
|
||||||
|
} from 'material-ui/Dialog'
|
||||||
|
import Button from 'material-ui/Button'
|
||||||
|
import RaisedButton from 'material-ui/Button'
|
||||||
|
import { grey } from 'material-ui/colors'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import MenuItem from 'material-ui/MenuItem'
|
import Tooltip from 'material-ui/Tooltip'
|
||||||
import SvgRemoveImage from 'material-ui/svg-icons/content/remove-circle'
|
import { MenuList, MenuItem } from 'material-ui/Menu'
|
||||||
import SvgCamera from 'material-ui/svg-icons/image/photo-camera'
|
import SvgRemoveImage from 'material-ui-icons/removeCircle'
|
||||||
import IconMenu from 'material-ui/IconMenu'
|
import SvgCamera from 'material-ui-icons/photoCamera'
|
||||||
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'
|
import MoreVertIcon from 'material-ui-icons/moreVert'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
import { Manager, Target, Popper } from 'react-popper'
|
||||||
|
import Grow from 'material-ui/transitions/Grow'
|
||||||
|
import ClickAwayListener from 'material-ui/utils/ClickAwayListener'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import ImageGallery from 'components/imageGallery'
|
import ImageGallery from 'components/imageGallery'
|
||||||
@@ -31,37 +49,72 @@ import { IPostWriteComponentProps } from './IPostWriteComponentProps'
|
|||||||
import { IPostWriteComponentState } from './IPostWriteComponentState'
|
import { IPostWriteComponentState } from './IPostWriteComponentState'
|
||||||
import { Post } from 'core/domain/posts'
|
import { Post } from 'core/domain/posts'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
backdrop: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
zIndex: '-1',
|
||||||
|
position: 'fixed',
|
||||||
|
willChange: 'opacity',
|
||||||
|
backgroundColor: 'rgba(251, 249, 249, 0.5)',
|
||||||
|
WebkitTapHighlightColor: 'transparent'
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
padding: 0,
|
||||||
|
paddingTop: 0
|
||||||
|
},
|
||||||
|
dialogRoot: {
|
||||||
|
paddingTop: 0
|
||||||
|
},
|
||||||
|
popperOpen: {
|
||||||
|
zIndex: 10
|
||||||
|
},
|
||||||
|
popperClose: {
|
||||||
|
pointerEvents: 'none',
|
||||||
|
zIndex: 0
|
||||||
|
},
|
||||||
|
author: {
|
||||||
|
paddingRight: 70
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// - Create PostWrite component class
|
// - Create PostWrite component class
|
||||||
export class PostWriteComponent extends Component<IPostWriteComponentProps,IPostWriteComponentState> {
|
export class PostWriteComponent extends Component<IPostWriteComponentProps, IPostWriteComponentState> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component constructor
|
* Component constructor
|
||||||
* @param {object} props is an object properties of component
|
* @param {object} props is an object properties of component
|
||||||
*/
|
*/
|
||||||
constructor (props: IPostWriteComponentProps) {
|
constructor(props: IPostWriteComponentProps) {
|
||||||
|
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
const {postModel} = props
|
const { postModel } = props
|
||||||
|
|
||||||
// Default state
|
// Default state
|
||||||
this.state = {
|
this.state = {
|
||||||
/**
|
/**
|
||||||
* Post text
|
* Post text
|
||||||
*/
|
*/
|
||||||
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '' ) : '',
|
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '') : '',
|
||||||
/**
|
/**
|
||||||
* The URL image of the post
|
* The URL image of the post
|
||||||
*/
|
*/
|
||||||
image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '' ) : '',
|
image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '') : '',
|
||||||
/**
|
/**
|
||||||
* The path identifier of image on the server
|
* The path identifier of image on the server
|
||||||
*/
|
*/
|
||||||
imageFullPath: this.props.edit && postModel ? (postModel.imageFullPath ? postModel.imageFullPath! : '' ) : '',
|
imageFullPath: this.props.edit && postModel ? (postModel.imageFullPath ? postModel.imageFullPath! : '') : '',
|
||||||
/**
|
/**
|
||||||
* If it's true gallery will be open
|
* If it's true gallery will be open
|
||||||
*/
|
*/
|
||||||
galleryOpen: false,
|
galleryOpen: false,
|
||||||
|
/**
|
||||||
|
* Whether menu is open
|
||||||
|
*/
|
||||||
|
menuOpen: false,
|
||||||
/**
|
/**
|
||||||
* If it's true post button will be disabled
|
* If it's true post button will be disabled
|
||||||
*/
|
*/
|
||||||
@@ -143,13 +196,13 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
ownerAvatar,
|
ownerAvatar,
|
||||||
ownerDisplayName,
|
ownerDisplayName,
|
||||||
edit,
|
edit,
|
||||||
onRequestClose,
|
onRequestClose,
|
||||||
post,
|
post,
|
||||||
update,
|
update,
|
||||||
postModel
|
postModel
|
||||||
} = this.props
|
} = this.props
|
||||||
if (image === '' && postText.trim() === '') {
|
if (image === '' && postText.trim() === '') {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -217,7 +270,8 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
|||||||
* @param {event} evt is an event passed by change post text callback funciton
|
* @param {event} evt is an event passed by change post text callback funciton
|
||||||
* @param {string} data is the post content which user writes
|
* @param {string} data is the post content which user writes
|
||||||
*/
|
*/
|
||||||
handleOnChange = (event: any, data: any) => {
|
handleOnChange = (event: any) => {
|
||||||
|
const data = event.target.value
|
||||||
this.setState({ postText: data })
|
this.setState({ postText: data })
|
||||||
if (data.length === 0 || data.trim() === '' || (this.props.edit && data.trim() === this.props.text)) {
|
if (data.length === 0 || data.trim() === '' || (this.props.edit && data.trim() === this.props.text)) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -251,37 +305,55 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps: IPostWriteComponentProps) {
|
/**
|
||||||
|
* Handle open more menu
|
||||||
|
*/
|
||||||
|
handleOpenMenu = () => {
|
||||||
|
this.setState({
|
||||||
|
menuOpen: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle close more menu
|
||||||
|
*/
|
||||||
|
handleCloseMenu = () => {
|
||||||
|
this.setState({
|
||||||
|
menuOpen: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps: IPostWriteComponentProps) {
|
||||||
if (!nextProps.open) {
|
if (!nextProps.open) {
|
||||||
const {postModel} = this.props
|
const { postModel } = this.props
|
||||||
this.setState({
|
this.setState({
|
||||||
/**
|
/**
|
||||||
* Post text
|
* Post text
|
||||||
*/
|
*/
|
||||||
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '' ) : '',
|
postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '') : '',
|
||||||
/**
|
/**
|
||||||
* The URL image of the post
|
* The URL image of the post
|
||||||
*/
|
*/
|
||||||
image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '' ) : '',
|
image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '') : '',
|
||||||
/**
|
/**
|
||||||
* The path identifier of image on the server
|
* The path identifier of image on the server
|
||||||
*/
|
*/
|
||||||
imageFullPath: this.props.edit && postModel ? (postModel.imageFullPath ? postModel.imageFullPath! : '' ) : '',
|
imageFullPath: this.props.edit && postModel ? (postModel.imageFullPath ? postModel.imageFullPath! : '') : '',
|
||||||
/**
|
/**
|
||||||
* If it's true gallery will be open
|
* If it's true gallery will be open
|
||||||
*/
|
*/
|
||||||
galleryOpen: false,
|
galleryOpen: false,
|
||||||
/**
|
/**
|
||||||
* If it's true post button will be disabled
|
* If it's true post button will be disabled
|
||||||
*/
|
*/
|
||||||
disabledPost: true,
|
disabledPost: true,
|
||||||
/**
|
/**
|
||||||
* If it's true comment will be disabled on post
|
* If it's true comment will be disabled on post
|
||||||
*/
|
*/
|
||||||
disableComments: this.props.edit && postModel ? postModel.disableComments! : false,
|
disableComments: this.props.edit && postModel ? postModel.disableComments! : false,
|
||||||
/**
|
/**
|
||||||
* If it's true share will be disabled on post
|
* If it's true share will be disabled on post
|
||||||
*/
|
*/
|
||||||
disableSharing: this.props.edit && postModel ? postModel.disableSharing! : false
|
disableSharing: this.props.edit && postModel ? postModel.disableSharing! : false
|
||||||
|
|
||||||
})
|
})
|
||||||
@@ -292,28 +364,44 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
|||||||
* Reneder component DOM
|
* Reneder component DOM
|
||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render() {
|
||||||
|
|
||||||
const iconButtonElement = (
|
const { classes } = this.props
|
||||||
<IconButton
|
const { menuOpen } = this.state
|
||||||
touch={true}
|
|
||||||
tooltip='more'
|
|
||||||
tooltipPosition='bottom-left'
|
|
||||||
>
|
|
||||||
<MoreVertIcon color={grey400} />
|
|
||||||
</IconButton>
|
|
||||||
)
|
|
||||||
|
|
||||||
const rightIconMenu = (
|
const rightIconMenu = (
|
||||||
<IconMenu iconButtonElement={iconButtonElement}>
|
<Manager>
|
||||||
<MenuItem onClick={this.handleToggleComments} style={{ fontSize: '14px' }}>{!this.state.disableComments ? 'Disable comments' : 'Enable comments'} </MenuItem>
|
<Target>
|
||||||
<MenuItem onClick={this.handleToggleSharing} style={{ fontSize: '14px' }}>{!this.state.disableSharing ? 'Disable sharing' : 'Enable sharing'}</MenuItem>
|
<Tooltip id='tooltip-icon' title='more' placement='bottom-start'>
|
||||||
</IconMenu>
|
<IconButton
|
||||||
|
onClick={this.handleOpenMenu}
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Target>
|
||||||
|
<Popper
|
||||||
|
placement='bottom-start'
|
||||||
|
eventsEnabled={menuOpen}
|
||||||
|
className={classNames({ [classes.popperClose]: !menuOpen }, { [classes.popperOpen]: menuOpen })}
|
||||||
|
>
|
||||||
|
<ClickAwayListener onClickAway={this.handleCloseMenu}>
|
||||||
|
<Grow in={menuOpen} style={{ transformOrigin: '0 0 0' }}>
|
||||||
|
<Paper>
|
||||||
|
<MenuList role='menu'>
|
||||||
|
<MenuItem onClick={this.handleToggleComments} style={{ fontSize: '14px' }}>{!this.state.disableComments ? 'Disable comments' : 'Enable comments'} </MenuItem>
|
||||||
|
<MenuItem onClick={this.handleToggleSharing} style={{ fontSize: '14px' }}>{!this.state.disableSharing ? 'Disable sharing' : 'Enable sharing'}</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Popper>
|
||||||
|
</Manager>
|
||||||
)
|
)
|
||||||
let postAvatar = <UserAvatarComponent fullName={this.props.ownerDisplayName!} fileName={this.props.ownerAvatar!} style={{ top: '8px' }} size={40} />
|
let postAvatar = <UserAvatarComponent fullName={this.props.ownerDisplayName!} fileName={this.props.ownerAvatar!} size={36} />
|
||||||
|
|
||||||
let author = (
|
let author = (
|
||||||
<div>
|
<div className={classes.author}>
|
||||||
<span style={{
|
<span style={{
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
paddingRight: '10px',
|
paddingRight: '10px',
|
||||||
@@ -321,7 +409,6 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
|||||||
color: 'rgba(0,0,0,0.87)',
|
color: 'rgba(0,0,0,0.87)',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
paddingLeft: '50px',
|
|
||||||
lineHeight: '25px'
|
lineHeight: '25px'
|
||||||
}}>{this.props.ownerDisplayName}</span><span style={{
|
}}>{this.props.ownerDisplayName}</span><span style={{
|
||||||
fontWeight: 100,
|
fontWeight: 100,
|
||||||
@@ -330,32 +417,32 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const writeActions = [
|
/**
|
||||||
<FlatButton
|
* Provide post image
|
||||||
label='Cancel'
|
*/
|
||||||
primary={true}
|
const loadImage = (this.state.image && this.state.image !== '')
|
||||||
keyboardFocused={false}
|
? (<div>
|
||||||
onTouchTap={this.props.onRequestClose}
|
<div style={{ position: 'relative', overflowY: 'hidden', overflowX: 'auto' }}>
|
||||||
style={{ color: grey800 }}
|
<ul style={{ position: 'relative', whiteSpace: 'nowrap', padding: '0 0 0 16px', margin: '8px 0 0 0', paddingRight: '16px', verticalAlign: 'bottom', flexShrink: 0, listStyleType: 'none' }}>
|
||||||
/>,
|
<div style={{ display: 'flex', position: 'relative' }}>
|
||||||
<FlatButton
|
<span onClick={this.handleRemoveImage} style={{
|
||||||
label={this.props.edit ? 'UPDATE' : 'POST'}
|
position: 'absolute', width: '28px', backgroundColor: 'rgba(255, 255, 255, 0.22)',
|
||||||
primary={true}
|
height: '28px', right: 12, top: 4, cursor: 'pointer', borderRadius: '50%',
|
||||||
keyboardFocused={false}
|
display: 'flex', alignItems: 'center', justifyContent: 'center'
|
||||||
onTouchTap={this.handlePost}
|
}}>
|
||||||
disabled={this.state.disabledPost}
|
<SvgRemoveImage style={{ color: 'rgba(0, 0, 0, 0.53)' }} />
|
||||||
/>
|
</span>
|
||||||
]
|
|
||||||
|
|
||||||
const galleryActions = [
|
<div style={{ display: 'inline-block', width: '100%', marginRight: '8px', transition: 'transform .25s' }}>
|
||||||
<FlatButton
|
<li style={{ width: '100%', margin: 0, verticalAlign: 'bottom', position: 'static' }}>
|
||||||
label='Cancel'
|
<Img fileName={this.state.image} style={{ width: '100%', height: 'auto' }} />
|
||||||
primary={true}
|
</li>
|
||||||
keyboardFocused={false}
|
</div>
|
||||||
onTouchTap={this.handleCloseGallery}
|
</div>
|
||||||
style={{ color: grey800 }}
|
|
||||||
/>
|
</ul>
|
||||||
]
|
</div>
|
||||||
|
</div>) : ''
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
dialog: {
|
dialog: {
|
||||||
@@ -369,88 +456,94 @@ export class PostWriteComponent extends Component<IPostWriteComponentProps,IPost
|
|||||||
<div style={this.props.style}>
|
<div style={this.props.style}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
<Dialog
|
<Dialog
|
||||||
|
BackdropProps={{className: classes.backdrop} as any}
|
||||||
key={this.props.id || 0}
|
key={this.props.id || 0}
|
||||||
actions={writeActions}
|
|
||||||
modal={false}
|
|
||||||
open={this.props.open}
|
open={this.props.open}
|
||||||
contentStyle={styles.dialog}
|
onClose={this.props.onRequestClose}
|
||||||
onRequestClose={this.props.onRequestClose}
|
|
||||||
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
|
|
||||||
bodyStyle={{ padding: 0 }}
|
|
||||||
autoDetectWindowHeight={false}
|
|
||||||
actionsContainerStyle={{ borderTop: '1px solid rgb(224, 224, 224)' }}
|
|
||||||
|
|
||||||
>
|
>
|
||||||
|
<DialogContent
|
||||||
|
className={classes.root}
|
||||||
|
style={{paddingTop: 0}}
|
||||||
|
|
||||||
<ListItem
|
>
|
||||||
disabled={true}
|
|
||||||
|
|
||||||
leftAvatar={postAvatar}
|
<Card elevation={0}>
|
||||||
rightIconButton={rightIconMenu}
|
<CardHeader
|
||||||
primaryText={author}
|
title={author}
|
||||||
style={{ padding: '16px 4px 30px 16px' }}
|
avatar={postAvatar}
|
||||||
/>
|
action={rightIconMenu}
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', flexGrow: 1, overflow: 'hidden' }}>
|
>
|
||||||
<div style={{ position: 'relative', flexDirection: 'column', display: 'flex', flexGrow: 1, overflow: 'hidden', overflowY: 'auto', maxHeight: '300px' }}>
|
</CardHeader>
|
||||||
<TextField
|
<CardContent>
|
||||||
value={this.state.postText}
|
<div style={{ display: 'flex', flexDirection: 'column', flexGrow: 1, overflow: 'hidden' }}>
|
||||||
onChange={this.handleOnChange}
|
<div style={{ position: 'relative', flexDirection: 'column', display: 'flex', flexGrow: 1, overflow: 'hidden', overflowY: 'auto', maxHeight: '300px' }}>
|
||||||
hintText='What is new with you?'
|
<TextField
|
||||||
underlineShow={false}
|
autoFocus
|
||||||
multiLine={true}
|
value={this.state.postText}
|
||||||
rows={2}
|
onChange={this.handleOnChange}
|
||||||
hintStyle={{ fontWeight: 200, fontSize: '14px' }}
|
placeholder='What is new with you?'
|
||||||
textareaStyle={{ fontWeight: 200, fontSize: '14px' }}
|
multiline
|
||||||
style={{ margin: '0 16px', flexShrink: 0, width: 'initial', flexGrow: 1 }}
|
rows={2}
|
||||||
|
rowsMax={4}
|
||||||
|
style={{ fontWeight: 200, fontSize: '14px', margin: '0 16px', flexShrink: 0, width: 'initial', flexGrow: 1 }}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{(this.state.image && this.state.image !== '')
|
{loadImage}
|
||||||
? (<div>
|
</div>
|
||||||
<div style={{ position: 'relative', overflowY: 'hidden', overflowX: 'auto' }}>
|
<div style={{ flexShrink: 0, boxFlex: 0, flexGrow: 0, maxHeight: '48px', width: '100%' }}>
|
||||||
<ul style={{ position: 'relative', whiteSpace: 'nowrap', padding: '0 0 0 16px', margin: '8px 0 0 0', paddingRight: '16px', verticalAlign: 'bottom', flexShrink: 0, listStyleType: 'none' }}>
|
<div style={{ flexDirection: 'row', display: 'flex' }}>
|
||||||
<div style={{ display: 'flex', position: 'relative' }}>
|
<div onClick={this.handleOpenGallery} style={{ outline: 'none', width: '48px', zIndex: 0, overflow: 'hidden', position: 'relative', textAlign: 'center', transition: 'background .3s', border: 0, borderRadius: '50%', display: 'inlineBlock', height: '48px' }}>
|
||||||
<span onClick={this.handleRemoveImage} style={{
|
<span style={{ top: '15px', display: 'block', position: 'relative', cursor: 'pointer' }}>
|
||||||
position: 'absolute', width: '28px', backgroundColor: 'rgba(255, 255, 255, 0.22)',
|
<SvgCamera style={{ color: 'grey' }} />
|
||||||
height: '28px', right: 12, top: 4, cursor: 'pointer', borderRadius: '50%',
|
</span>
|
||||||
display: 'flex', alignItems: 'center', justifyContent: 'center'
|
</div>
|
||||||
}}>
|
</div>
|
||||||
<SvgRemoveImage hoverColor='rgba(0, 0, 0, 0.65)' style={{ color: 'rgba(0, 0, 0, 0.53)' }} />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div style={{ display: 'inline-block', width: '100%', marginRight: '8px', transition: 'transform .25s' }}>
|
|
||||||
<li style={{ width: '100%', margin: 0, verticalAlign: 'bottom', position: 'static' }}>
|
|
||||||
<Img fileName={this.state.image} style={{ width: '100%', height: 'auto' }} />
|
|
||||||
</li>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>) : ''}
|
|
||||||
</div>
|
|
||||||
<div style={{ flexShrink: 0, boxFlex: 0, flexGrow: 0, maxHeight: '48px', width: '100%' }}>
|
|
||||||
<div style={{ flexDirection: 'row', display: 'flex' }}>
|
|
||||||
<div onClick={this.handleOpenGallery} style={{ outline: 'none', width: '48px', zIndex: 0, overflow: 'hidden', position: 'relative', textAlign: 'center', transition: 'background .3s', border: 0, borderRadius: '50%', display: 'inlineBlock', height: '48px' }}>
|
|
||||||
<span style={{ top: '15px', display: 'block', position: 'relative', cursor: 'pointer' }}>
|
|
||||||
<SvgCamera color='grey' />
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</CardContent>
|
||||||
</div>
|
</Card>
|
||||||
</div>
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
color='primary'
|
||||||
|
disableFocusRipple={true}
|
||||||
|
disableRipple={true}
|
||||||
|
onClick={this.props.onRequestClose}
|
||||||
|
style={{ color: grey[800] }}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
color='primary'
|
||||||
|
disableFocusRipple={true}
|
||||||
|
disableRipple={true}
|
||||||
|
onClick={this.handlePost}
|
||||||
|
disabled={this.state.disabledPost}
|
||||||
|
>
|
||||||
|
{this.props.edit ? 'UPDATE' : 'POST'}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<Dialog
|
<Dialog
|
||||||
actions={galleryActions}
|
|
||||||
modal={false}
|
|
||||||
open={this.state.galleryOpen}
|
open={this.state.galleryOpen}
|
||||||
contentStyle={styles.dialog}
|
onClose={this.handleCloseGallery}
|
||||||
onRequestClose={this.handleCloseGallery}
|
|
||||||
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
|
|
||||||
autoDetectWindowHeight={false}
|
|
||||||
|
|
||||||
>
|
>
|
||||||
<ImageGallery set={this.onRequestSetImage} close={this.handleCloseGallery} />
|
<DialogContent>
|
||||||
|
<ImageGallery set={this.onRequestSetImage} close={this.handleCloseGallery} />
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
color='primary'
|
||||||
|
disableFocusRipple={true}
|
||||||
|
disableRipple={true}
|
||||||
|
onClick={this.handleCloseGallery}
|
||||||
|
style={{ color: grey[800] }}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -486,4 +579,4 @@ const mapStateToProps = (state: any, ownProps: IPostWriteComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(PostWriteComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(PostWriteComponent as any) as any)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import React, { Component } from 'react'
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import Dialog from 'material-ui/Dialog'
|
import Dialog from 'material-ui/Dialog'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import ProfileHeader from 'components/profileHeader'
|
import ProfileHeader from 'components/profileHeader'
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { grey400 } from 'material-ui/styles/colors'
|
import { grey400 } from 'material-ui/styles/colors'
|
||||||
import SvgClose from 'material-ui/svg-icons/navigation/close'
|
import SvgClose from 'material-ui-icons/close'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import Divider from 'material-ui/Divider'
|
import Divider from 'material-ui/Divider'
|
||||||
import { IDialogTitleComponentProps } from './IDialogTitleComponentProps'
|
import { IDialogTitleComponentProps } from './IDialogTitleComponentProps'
|
||||||
import { IDialogTitleComponentState } from './IDialogTitleComponentState'
|
import { IDialogTitleComponentState } from './IDialogTitleComponentState'
|
||||||
@@ -82,7 +82,7 @@ export default class DialogTitleComponent extends Component<IDialogTitleComponen
|
|||||||
{title || ''}
|
{title || ''}
|
||||||
</div>
|
</div>
|
||||||
{ buttonLabel ? (<div style={{ marginTop: '-9px' }}>
|
{ buttonLabel ? (<div style={{ marginTop: '-9px' }}>
|
||||||
<FlatButton label={buttonLabel || ''} primary={true} disabled={disabledButton ? disabledButton : false} onClick={onClickButton || (x => x)} />
|
<Button label={buttonLabel || ''} color='primary' disabled={disabledButton ? disabledButton : false} onClick={onClickButton || (x => x)} />
|
||||||
</div>) : ''}
|
</div>) : ''}
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { grey400, darkBlack, lightBlack } from 'material-ui/styles/colors'
|
import { grey } from 'material-ui/colors'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'
|
import MoreVertIcon from 'material-ui-icons/moreVert'
|
||||||
import IconMenu from 'material-ui/IconMenu'
|
import { MenuList, MenuItem } from 'material-ui/Menu'
|
||||||
import MenuItem from 'material-ui/MenuItem'
|
import Button from 'material-ui/Button'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
|
||||||
import EventListener, { withOptions } from 'react-event-listener'
|
import EventListener, { withOptions } from 'react-event-listener'
|
||||||
import { Parallax, Background } from 'react-parallax'
|
import { Parallax, Background } from 'react-parallax'
|
||||||
|
|
||||||
@@ -152,19 +151,18 @@ export class ProfileHeaderComponent extends Component<IProfileHeaderComponentPro
|
|||||||
}
|
}
|
||||||
|
|
||||||
const iconButtonElement = (
|
const iconButtonElement = (
|
||||||
<IconButton style={this.state.isSmall ? styles.iconButtonSmall : styles.iconButton} iconStyle={this.state.isSmall ? styles.iconButtonSmall : styles.iconButton}
|
<IconButton style={this.state.isSmall ? styles.iconButtonSmall : styles.iconButton}>
|
||||||
touch={true}
|
<MoreVertIcon style={{...(this.state.isSmall ? styles.iconButtonSmall : styles.iconButton), color: grey[400]}} viewBox='10 0 24 24' />
|
||||||
>
|
|
||||||
<MoreVertIcon color={grey400} viewBox='10 0 24 24' />
|
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)
|
)
|
||||||
|
|
||||||
const RightIconMenu = () => (
|
const RightIconMenu = () => (
|
||||||
<IconMenu iconButtonElement={iconButtonElement}>
|
<div>
|
||||||
|
{iconButtonElement}
|
||||||
<MenuItem style={{ fontSize: '14px' }}>Reply</MenuItem>
|
<MenuItem style={{ fontSize: '14px' }}>Reply</MenuItem>
|
||||||
<MenuItem style={{ fontSize: '14px' }}>Edit</MenuItem>
|
<MenuItem style={{ fontSize: '14px' }}>Edit</MenuItem>
|
||||||
<MenuItem style={{ fontSize: '14px' }}>Delete</MenuItem>
|
<MenuItem style={{ fontSize: '14px' }}>Delete</MenuItem>
|
||||||
</IconMenu>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {isAuthedUser} = this.props
|
const {isAuthedUser} = this.props
|
||||||
@@ -200,7 +198,11 @@ export class ProfileHeaderComponent extends Component<IProfileHeaderComponentPro
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='right'>
|
<div className='right'>
|
||||||
{isAuthedUser ? (<div style={this.state.isSmall ? styles.editButtonSmall : styles.editButton}><RaisedButton label='EDIT PROFILE' onClick={this.props.openEditor} /></div>) : ''}
|
{isAuthedUser ? (<div style={this.state.isSmall ? styles.editButtonSmall : styles.editButton}>
|
||||||
|
<Button raised onClick={this.props.openEditor}>
|
||||||
|
EDIT PROFILE
|
||||||
|
</Button>
|
||||||
|
</div>) : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isAuthedUser ? (<EditProfile
|
{isAuthedUser ? (<EditProfile
|
||||||
|
|||||||
@@ -13,4 +13,9 @@ export interface IResetPasswordComponentProps {
|
|||||||
* @memberof IResetPasswordComponentProps
|
* @memberof IResetPasswordComponentProps
|
||||||
*/
|
*/
|
||||||
loginPage?: () => void
|
loginPage?: () => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,27 @@ import { NavLink, withRouter } from 'react-router-dom'
|
|||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
import Typography from 'material-ui/Typography'
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
import * as authorizeActions from 'actions/authorizeActions'
|
import * as authorizeActions from 'actions/authorizeActions'
|
||||||
import { IResetPasswordComponentProps } from './IResetPasswordComponentProps'
|
import { IResetPasswordComponentProps } from './IResetPasswordComponentProps'
|
||||||
import { IResetPasswordComponentState } from './IResetPasswordComponentState'
|
import { IResetPasswordComponentState } from './IResetPasswordComponentState'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
textField: {
|
||||||
|
minWidth: 280,
|
||||||
|
marginTop: 20
|
||||||
|
|
||||||
|
},
|
||||||
|
caption: {
|
||||||
|
marginTop: 30
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*
|
*
|
||||||
@@ -77,6 +89,8 @@ export class ResetPasswordComponent extends Component<IResetPasswordComponentPro
|
|||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
|
|
||||||
|
const {classes} = this.props
|
||||||
|
|
||||||
const paperStyle = {
|
const paperStyle = {
|
||||||
minHeight: 370,
|
minHeight: 370,
|
||||||
width: 450,
|
width: 450,
|
||||||
@@ -98,7 +112,7 @@ export class ResetPasswordComponent extends Component<IResetPasswordComponentPro
|
|||||||
}}>Green</h1>
|
}}>Green</h1>
|
||||||
|
|
||||||
<div className='animate-bottom'>
|
<div className='animate-bottom'>
|
||||||
<Paper style={paperStyle} zDepth={1} rounded={false} >
|
<Paper style={paperStyle} elevation={1}>
|
||||||
<div style={{ padding: '48px 40px 36px' }}>
|
<div style={{ padding: '48px 40px 36px' }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
paddingLeft: '40px',
|
paddingLeft: '40px',
|
||||||
@@ -116,24 +130,29 @@ export class ResetPasswordComponent extends Component<IResetPasswordComponentPro
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
|
className={classes.textField}
|
||||||
|
autoFocus
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.emailInputError}
|
helperText={this.state.emailInputError}
|
||||||
|
error={this.state.emailInputError.trim() !== ''}
|
||||||
name='emailInput'
|
name='emailInput'
|
||||||
floatingLabelStyle={{ fontSize: '15px' }}
|
label='Email'
|
||||||
floatingLabelText='Email'
|
|
||||||
type='email'
|
type='email'
|
||||||
/><br />
|
/><br />
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<div className='settings__button-box'>
|
<div className='settings__button-box'>
|
||||||
<div>
|
<div>
|
||||||
<FlatButton label='Back' onClick={this.props.loginPage} />
|
<Button onClick={this.props.loginPage}> Back </Button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<RaisedButton label='Reset password' primary={true} onClick={this.handleForm} />
|
<Button raised color='primary' onClick={this.handleForm}> Reset password </Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Typography className={classes.caption} type='caption' component='p'>
|
||||||
|
Please put your email and click on "RESET PASSWORD". If not click on "BACK".
|
||||||
|
We will send you an email contains the link of the reset password.
|
||||||
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
</div>
|
</div>
|
||||||
@@ -170,4 +189,4 @@ const mapStateToProps = (state: any, ownProps: IResetPasswordComponentProps) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(ResetPasswordComponent as any))
|
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(ResetPasswordComponent as any) as any))
|
||||||
|
|||||||
@@ -16,15 +16,15 @@ export interface ISendFeedbackComponentProps {
|
|||||||
/**
|
/**
|
||||||
* Hide feedback form
|
* Hide feedback form
|
||||||
*/
|
*/
|
||||||
hideFeedback: () => any
|
hideFeedback?: () => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The server request of send feedback
|
* The server request of send feedback
|
||||||
*/
|
*/
|
||||||
sendFeedbackRequest: ServerRequestModel
|
sendFeedbackRequest?: ServerRequestModel
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current user profile
|
* Current user profile
|
||||||
*/
|
*/
|
||||||
currentUser: Profile
|
currentUser?: Profile
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import { connect } from 'react-redux'
|
|||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import SvgHappy from 'material-ui/svg-icons/image/tag-faces'
|
import SvgHappy from 'material-ui-icons/tagFaces'
|
||||||
import SvgSad from 'material-ui/svg-icons/action/face'
|
import SvgSad from 'material-ui-icons/face'
|
||||||
import SvgClose from 'material-ui/svg-icons/content/clear'
|
import SvgClose from 'material-ui-icons/clear'
|
||||||
import RefreshIndicator from 'material-ui/RefreshIndicator'
|
import { CircularProgress } from 'material-ui/Progress'
|
||||||
|
import Tooltip from 'material-ui/Tooltip'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ export class SendFeedbackComponent extends Component<ISendFeedbackComponentProps
|
|||||||
* Component constructor
|
* Component constructor
|
||||||
* @param {object} props is an object properties of component
|
* @param {object} props is an object properties of component
|
||||||
*/
|
*/
|
||||||
constructor(props: ISendFeedbackComponentProps) {
|
constructor (props: ISendFeedbackComponentProps) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
// Defaul state
|
// Defaul state
|
||||||
@@ -75,44 +76,47 @@ export class SendFeedbackComponent extends Component<ISendFeedbackComponentProps
|
|||||||
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest } = this.props
|
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest } = this.props
|
||||||
const { feedText } = this.state
|
const { feedText } = this.state
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className='main-box'>
|
||||||
<TextField
|
<TextField
|
||||||
hintText='What do you feel?'
|
placeholder='What do you feel?'
|
||||||
multiLine={true}
|
multiline
|
||||||
onChange={this.handleFeedText}
|
onChange={this.handleFeedText}
|
||||||
rows={2}
|
rows={2}
|
||||||
rowsMax={4}
|
rowsMax={4}
|
||||||
/><br />
|
autoFocus
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
<div className='buttons'>
|
<div className='buttons'>
|
||||||
|
<Tooltip title='Sad' placement='bottom-start'>
|
||||||
<IconButton
|
<IconButton
|
||||||
tooltip='sad'
|
className='flaticon-sad-2 icon__svg'
|
||||||
iconClassName='flaticon-sad-2 icon__svg'
|
|
||||||
tooltipPosition='bottom-left'
|
|
||||||
onClick={() => this.handleSendFeed(FeedType.Sad)}
|
onClick={() => this.handleSendFeed(FeedType.Sad)}
|
||||||
>
|
>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip title='Acceptable' placement='bottom-start'>
|
||||||
<IconButton
|
<IconButton
|
||||||
tooltip='acceptable'
|
className='flaticon-neutral icon__svg'
|
||||||
iconClassName='flaticon-neutral icon__svg'
|
|
||||||
tooltipPosition='bottom-left'
|
|
||||||
onClick={() => this.handleSendFeed(FeedType.Acceptable)}
|
onClick={() => this.handleSendFeed(FeedType.Acceptable)}
|
||||||
>
|
>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title='Happy' placement='bottom-start'>
|
||||||
<IconButton
|
<IconButton
|
||||||
tooltip='happy'
|
className='flaticon-happy-2 icon__svg'
|
||||||
iconClassName='flaticon-happy-2 icon__svg'
|
|
||||||
tooltipPosition='bottom-left'
|
|
||||||
onClick={() => this.handleSendFeed(FeedType.Happy)}
|
onClick={() => this.handleSendFeed(FeedType.Happy)}
|
||||||
>
|
>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title='Awesome' placement='bottom-start'>
|
||||||
<IconButton
|
<IconButton
|
||||||
tooltip='awesome'
|
className='flaticon-happy icon__svg'
|
||||||
iconClassName='flaticon-happy icon__svg'
|
|
||||||
tooltipPosition='bottom-left'
|
|
||||||
onClick={() => this.handleSendFeed(FeedType.Awesome)}
|
onClick={() => this.handleSendFeed(FeedType.Awesome)}
|
||||||
>
|
>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div >)
|
</div >)
|
||||||
}
|
}
|
||||||
@@ -123,13 +127,14 @@ export class SendFeedbackComponent extends Component<ISendFeedbackComponentProps
|
|||||||
Your feedback is sending!
|
Your feedback is sending!
|
||||||
</p>
|
</p>
|
||||||
<div className='icon'>
|
<div className='icon'>
|
||||||
<RefreshIndicator
|
<CircularProgress
|
||||||
size={50}
|
color='secondary'
|
||||||
left={70}
|
size={50}
|
||||||
top={0}
|
mode='determinate'
|
||||||
status='loading'
|
value={25}
|
||||||
/>
|
min={0}
|
||||||
|
max={50}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
@@ -169,21 +174,21 @@ export class SendFeedbackComponent extends Component<ISendFeedbackComponentProps
|
|||||||
* Reneder component DOM
|
* Reneder component DOM
|
||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render() {
|
render () {
|
||||||
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest } = this.props
|
const { sendFeedbackStatus, hideFeedback, sendFeed, sendFeedbackRequest } = this.props
|
||||||
const { feedText } = this.state
|
const { feedText } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='sendFeedback__content animate__up' style={{ display: (sendFeedbackStatus ? 'block' : 'none') }}>
|
<div className='sendFeedback__content animate__up'>
|
||||||
<Paper className='paper' >
|
<Paper className='paper' >
|
||||||
<div className='close'>
|
<div className='close'>
|
||||||
|
<Tooltip title='Cancel' placement='bottom-start'>
|
||||||
<IconButton
|
<IconButton
|
||||||
tooltip='cancel'
|
onClick={() => hideFeedback!()}
|
||||||
tooltipPosition='bottom-left'
|
|
||||||
onClick={() => hideFeedback()}
|
|
||||||
>
|
>
|
||||||
<SvgClose />
|
<SvgClose />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
</Tooltip >
|
||||||
</div>
|
</div>
|
||||||
{this.getFeedbackForm()}
|
{this.getFeedbackForm()}
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,17 @@ export interface ISettingComponentProps {
|
|||||||
*
|
*
|
||||||
* @memberof ISettingComponentProps
|
* @memberof ISettingComponentProps
|
||||||
*/
|
*/
|
||||||
login: (email: string, password: string) => any
|
login?: (email: string, password: string) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redirect to home page
|
* Redirect to home page
|
||||||
*
|
*
|
||||||
* @memberof ISettingComponentProps
|
* @memberof ISettingComponentProps
|
||||||
*/
|
*/
|
||||||
homePage: () => void
|
homePage?: () => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,22 @@ import { NavLink, withRouter } from 'react-router-dom'
|
|||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
import * as authorizeActions from 'actions/authorizeActions'
|
import * as authorizeActions from 'actions/authorizeActions'
|
||||||
import { ISettingComponentProps } from './ISettingComponentProps'
|
import { ISettingComponentProps } from './ISettingComponentProps'
|
||||||
import { ISettingComponentState } from './ISettingComponentState'
|
import { ISettingComponentState } from './ISettingComponentState'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
textField: {
|
||||||
|
minWidth: 280,
|
||||||
|
marginTop: 20
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*
|
*
|
||||||
@@ -98,7 +106,7 @@ export class SettingComponent extends Component<ISettingComponentProps,ISettingC
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
this.props.login(
|
this.props.login!(
|
||||||
this.state.passwordInput,
|
this.state.passwordInput,
|
||||||
this.state.confirmInput
|
this.state.confirmInput
|
||||||
)
|
)
|
||||||
@@ -112,6 +120,7 @@ export class SettingComponent extends Component<ISettingComponentProps,ISettingC
|
|||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
|
|
||||||
|
const {classes} = this.props
|
||||||
const paperStyle = {
|
const paperStyle = {
|
||||||
minHeight: 370,
|
minHeight: 370,
|
||||||
width: 450,
|
width: 450,
|
||||||
@@ -133,7 +142,7 @@ export class SettingComponent extends Component<ISettingComponentProps,ISettingC
|
|||||||
}}>Green</h1>
|
}}>Green</h1>
|
||||||
|
|
||||||
<div className='animate-bottom'>
|
<div className='animate-bottom'>
|
||||||
<Paper style={paperStyle} zDepth={1} rounded={false} >
|
<Paper style={paperStyle} elevation={1} >
|
||||||
<div style={{ padding: '48px 40px 36px' }}>
|
<div style={{ padding: '48px 40px 36px' }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
paddingLeft: '40px',
|
paddingLeft: '40px',
|
||||||
@@ -142,38 +151,41 @@ export class SettingComponent extends Component<ISettingComponentProps,ISettingC
|
|||||||
|
|
||||||
<h2 style={{
|
<h2 style={{
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
paddingTop: '16px',
|
paddingTop: '10px',
|
||||||
fontSize: '24px',
|
fontSize: '24px',
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
lineHeight: '32px',
|
lineHeight: '32px',
|
||||||
margin: 0
|
margin: 0
|
||||||
}}>Change Password</h2>
|
}} className='zoomOutLCorner animated'>Change Password</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
|
autoFocus
|
||||||
|
className={classes.textField}
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.passwordInputError}
|
helperText={this.state.passwordInputError}
|
||||||
name='passwordInput'
|
name='passwordInput'
|
||||||
floatingLabelStyle={{ fontSize: '15px' }}
|
label='New password'
|
||||||
floatingLabelText='New password'
|
|
||||||
type='password'
|
type='password'
|
||||||
|
error={this.state.passwordInputError.trim() !== ''}
|
||||||
/><br />
|
/><br />
|
||||||
<TextField
|
<TextField
|
||||||
|
className={classes.textField}
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.confirmInputError}
|
helperText={this.state.confirmInputError}
|
||||||
name='confirmInput'
|
name='confirmInput'
|
||||||
floatingLabelStyle={{ fontSize: '15px' }}
|
label='Confirm password'
|
||||||
floatingLabelText='Confirm password'
|
|
||||||
type='password'
|
type='password'
|
||||||
|
error={this.state.confirmInputError.trim() !== ''}
|
||||||
/><br />
|
/><br />
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<div className='settings__button-box'>
|
<div className='settings__button-box'>
|
||||||
<div>
|
<div>
|
||||||
<FlatButton label='Home' onClick={this.props.homePage} />
|
<Button onClick={this.props.homePage} > Home </Button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<RaisedButton label='Change password' primary={true} onClick={this.handleForm} />
|
<Button raised color='primary' onClick={this.handleForm}> Change password </Button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -216,4 +228,4 @@ const mapStateToProps = (state: any, ownProps: ISettingComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(SettingComponent as any))
|
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(SettingComponent as any) as any))
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ export class SidebarComponent extends Component<ISidebarComponentProps,ISidebarC
|
|||||||
this.props.status(false)
|
this.props.status(false)
|
||||||
|
|
||||||
}
|
}
|
||||||
this.props.overlay((sizeCondition(width)) ? false : true)
|
this.props.overlay(!(sizeCondition(width)) && this.state.open ? true : false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,12 +174,12 @@ export class SidebarComponent extends Component<ISidebarComponentProps,ISidebarC
|
|||||||
}else {
|
}else {
|
||||||
this.setState({
|
this.setState({
|
||||||
overlayOpen: true,
|
overlayOpen: true,
|
||||||
overlay: true
|
overlay: this.state.open
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.setState({ sidebarClass: 'sidebar sidebar__over', overlay: true })
|
this.setState({ sidebarClass: 'sidebar sidebar__over', overlay: this.state.open })
|
||||||
this.props.overlay(true)
|
this.props.overlay(this.state.open!)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export default class SidebarMainComponent extends Component<ISidebarMainComponen
|
|||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className='home__main' style={this.props.cstyle} >
|
<div className='home__main' style={this.props.cstyle} >
|
||||||
<div style={{height: '64px', width: '100%'}}></div>
|
<div style={{height: '80px', width: '100%'}}></div>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,19 +5,24 @@ export interface ISignupComponentProps {
|
|||||||
*
|
*
|
||||||
* @memberof ISignupComponentState
|
* @memberof ISignupComponentState
|
||||||
*/
|
*/
|
||||||
showError: (message: string) => any
|
showError?: (message: string) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register user
|
* Register user
|
||||||
*
|
*
|
||||||
* @memberof ISignupComponentState
|
* @memberof ISignupComponentState
|
||||||
*/
|
*/
|
||||||
register: (data: any) => any
|
register?: (data: any) => any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login
|
* Login
|
||||||
*
|
*
|
||||||
* @memberof ISignupComponentState
|
* @memberof ISignupComponentState
|
||||||
*/
|
*/
|
||||||
loginPage: () => any
|
loginPage?: () => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import { push } from 'react-router-redux'
|
|||||||
import { NavLink, withRouter } from 'react-router-dom'
|
import { NavLink, withRouter } from 'react-router-dom'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
|
||||||
// - Import actions
|
// - Import actions
|
||||||
import * as authorizeActions from 'actions/authorizeActions'
|
import * as authorizeActions from 'actions/authorizeActions'
|
||||||
@@ -19,6 +20,14 @@ import { ISignupComponentProps } from './ISignupComponentProps'
|
|||||||
import { ISignupComponentState } from './ISignupComponentState'
|
import { ISignupComponentState } from './ISignupComponentState'
|
||||||
import { UserRegisterModel } from 'models/users/userRegisterModel'
|
import { UserRegisterModel } from 'models/users/userRegisterModel'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
textField: {
|
||||||
|
minWidth: 280,
|
||||||
|
marginTop: 20
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// - Create Signup component class
|
// - Create Signup component class
|
||||||
export class SignupComponent extends Component<ISignupComponentProps,ISignupComponentState> {
|
export class SignupComponent extends Component<ISignupComponentProps,ISignupComponentState> {
|
||||||
|
|
||||||
@@ -38,7 +47,6 @@ export class SignupComponent extends Component<ISignupComponentProps,ISignupComp
|
|||||||
passwordInputError: '',
|
passwordInputError: '',
|
||||||
confirmInput: '',
|
confirmInput: '',
|
||||||
confirmInputError: ''
|
confirmInputError: ''
|
||||||
|
|
||||||
}
|
}
|
||||||
// Binding function to `this`
|
// Binding function to `this`
|
||||||
this.handleForm = this.handleForm.bind(this)
|
this.handleForm = this.handleForm.bind(this)
|
||||||
@@ -145,7 +153,7 @@ export class SignupComponent extends Component<ISignupComponentProps,ISignupComp
|
|||||||
|
|
||||||
}
|
}
|
||||||
if (!error) {
|
if (!error) {
|
||||||
register({
|
register!({
|
||||||
email: emailInput,
|
email: emailInput,
|
||||||
password: passwordInput,
|
password: passwordInput,
|
||||||
fullName: fullNameInput
|
fullName: fullNameInput
|
||||||
@@ -159,6 +167,8 @@ export class SignupComponent extends Component<ISignupComponentProps,ISignupComp
|
|||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
|
|
||||||
|
const {classes} = this.props
|
||||||
const paperStyle = {
|
const paperStyle = {
|
||||||
minHeight: 500,
|
minHeight: 500,
|
||||||
width: 450,
|
width: 450,
|
||||||
@@ -182,7 +192,7 @@ export class SignupComponent extends Component<ISignupComponentProps,ISignupComp
|
|||||||
}}>Green</h1>
|
}}>Green</h1>
|
||||||
|
|
||||||
<div className='animate-bottom'>
|
<div className='animate-bottom'>
|
||||||
<Paper style={paperStyle} zDepth={1} rounded={false} >
|
<Paper style={paperStyle} elevation={1} >
|
||||||
<div style={{padding: '48px 40px 36px'}}>
|
<div style={{padding: '48px 40px 36px'}}>
|
||||||
<div style={{paddingLeft: '40px',
|
<div style={{paddingLeft: '40px',
|
||||||
paddingRight: '40px'}}>
|
paddingRight: '40px'}}>
|
||||||
@@ -197,44 +207,49 @@ export class SignupComponent extends Component<ISignupComponentProps,ISignupComp
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
|
className={classes.textField}
|
||||||
|
autoFocus
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.fullNameInputError}
|
helperText={this.state.fullNameInputError}
|
||||||
|
error={this.state.fullNameInputError.trim() !== ''}
|
||||||
name='fullNameInput'
|
name='fullNameInput'
|
||||||
floatingLabelStyle={{fontSize: '15px'}}
|
label='Full Name'
|
||||||
floatingLabelText='Full Name'
|
|
||||||
type='text'
|
type='text'
|
||||||
/><br />
|
/><br />
|
||||||
<TextField
|
<TextField
|
||||||
|
className={classes.textField}
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.emailInputError}
|
helperText={this.state.emailInputError}
|
||||||
|
error={this.state.emailInputError.trim() !== ''}
|
||||||
name='emailInput'
|
name='emailInput'
|
||||||
floatingLabelStyle={{fontSize: '15px'}}
|
label='Email'
|
||||||
floatingLabelText='Email'
|
|
||||||
type='email'
|
type='email'
|
||||||
/><br />
|
/><br />
|
||||||
<TextField
|
<TextField
|
||||||
|
className={classes.textField}
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.passwordInputError }
|
helperText={this.state.passwordInputError }
|
||||||
|
error={this.state.passwordInputError.trim() !== ''}
|
||||||
name='passwordInput'
|
name='passwordInput'
|
||||||
floatingLabelStyle={{fontSize: '15px'}}
|
label='Password'
|
||||||
floatingLabelText='Password'
|
|
||||||
type='password'
|
type='password'
|
||||||
/><br />
|
/><br />
|
||||||
<TextField
|
<TextField
|
||||||
|
className={classes.textField}
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
errorText={this.state.confirmInputError }
|
helperText={this.state.confirmInputError }
|
||||||
|
error={this.state.confirmInputError.trim() !== ''}
|
||||||
name='confirmInput'
|
name='confirmInput'
|
||||||
floatingLabelStyle={{fontSize: '15px'}}
|
label='Confirm Password'
|
||||||
floatingLabelText='Confirm Password'
|
|
||||||
type='password'
|
type='password'
|
||||||
/><br />
|
/><br />
|
||||||
<br />
|
<br />
|
||||||
<div className='signup__button-box'>
|
<div className='signup__button-box'>
|
||||||
<div>
|
<div>
|
||||||
<FlatButton label='Login' onClick={this.props.loginPage} />
|
<Button onClick={this.props.loginPage}> Login </Button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<RaisedButton label='Create' primary={true} onClick={this.handleForm}/>
|
<Button raised color='primary' onClick={this.handleForm}> Create </Button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -281,4 +296,4 @@ const mapStateToProps = (state: any,ownProps: ISignupComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(SignupComponent as any) as any)
|
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(withStyles(styles)(SignupComponent as any) as any))
|
||||||
|
|||||||
@@ -3,13 +3,11 @@ import React, { Component } from 'react'
|
|||||||
import { withRouter } from 'react-router-dom'
|
import { withRouter } from 'react-router-dom'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card'
|
import Button from 'material-ui/Button'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import { grey,teal } from 'material-ui/colors'
|
||||||
import { grey400, grey800, darkBlack, lightBlack,tealA400 } from 'material-ui/styles/colors'
|
import SvgCamera from 'material-ui-icons/photoCamera'
|
||||||
import CircularProgress from 'material-ui/CircularProgress'
|
|
||||||
import SvgCamera from 'material-ui/svg-icons/image/photo-camera'
|
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import { List, ListItem } from 'material-ui/List'
|
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List'
|
||||||
import InfiniteScroll from 'react-infinite-scroller'
|
import InfiniteScroll from 'react-infinite-scroller'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
@@ -50,11 +48,10 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
|||||||
|
|
||||||
styles = {
|
styles = {
|
||||||
postWritePrimaryText : {
|
postWritePrimaryText : {
|
||||||
color: grey400,
|
color: grey[400],
|
||||||
cursor: 'text'
|
cursor: 'text'
|
||||||
},
|
},
|
||||||
postWtireItem : {
|
postWtireItem : {
|
||||||
padding: '7px 0px',
|
|
||||||
fontWeight: '200'
|
fontWeight: '200'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,15 +217,18 @@ export class StreamComponent extends Component<IStreamComponentProps,IStreamComp
|
|||||||
<div className='grid-cell animate-top' style= {{maxWidth: '530px', minWidth: '280px'}}>
|
<div className='grid-cell animate-top' style= {{maxWidth: '530px', minWidth: '280px'}}>
|
||||||
{displayWriting && !tag
|
{displayWriting && !tag
|
||||||
? (<PostWriteComponent open={this.state.openPostWrite} onRequestClose={this.handleClosePostWrite} edit={false} >
|
? (<PostWriteComponent open={this.state.openPostWrite} onRequestClose={this.handleClosePostWrite} edit={false} >
|
||||||
<Paper zDepth={2} style={{ height: '68px', width: '100%' }}>
|
<Paper elevation={2}>
|
||||||
|
|
||||||
<ListItem
|
<ListItem button
|
||||||
primaryText={<span style={this.styles.postWritePrimaryText as any}> What's new with you? </span>}
|
|
||||||
leftAvatar={<UserAvatarComponent fullName={this.props.fullName!} fileName={this.props.avatar!} size={36} />}
|
|
||||||
rightIcon={<SvgCamera />}
|
|
||||||
style={this.styles.postWtireItem as any}
|
style={this.styles.postWtireItem as any}
|
||||||
onTouchTap={this.handleOpenPostWrite}
|
onClick={this.handleOpenPostWrite}
|
||||||
/>
|
>
|
||||||
|
<UserAvatarComponent fullName={this.props.fullName!} fileName={this.props.avatar!} size={36} />
|
||||||
|
<ListItemText inset primary={<span style={this.styles.postWritePrimaryText as any}> What's new with you? </span>} />
|
||||||
|
<ListItemIcon>
|
||||||
|
<SvgCamera />
|
||||||
|
</ListItemIcon>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
</Paper>
|
</Paper>
|
||||||
<div style={{ height: '16px' }}></div>
|
<div style={{ height: '16px' }}></div>
|
||||||
|
|||||||
@@ -19,5 +19,5 @@ export interface IUserAvatarComponentProps {
|
|||||||
/**
|
/**
|
||||||
* Trigger on touch tap
|
* Trigger on touch tap
|
||||||
*/
|
*/
|
||||||
onTouchTap?: Function
|
onClick?: (event: any) => anys
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export class UserAvatarComponent extends Component<IUserAvatarComponentProps,IUs
|
|||||||
/**
|
/**
|
||||||
* Trigger on touch tap
|
* Trigger on touch tap
|
||||||
*/
|
*/
|
||||||
onTouchTap: PropTypes.func
|
onClick: PropTypes.func
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,13 +64,13 @@ export class UserAvatarComponent extends Component<IUserAvatarComponentProps,IUs
|
|||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
let { fileName, fullName, style, size, onTouchTap } = this.props
|
let { fileName, fullName, style, size, onClick } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{display: 'inherit'}}>
|
<div style={{display: 'inherit'}}>
|
||||||
{(fileName && fileName !== '' && fileName !== 'noImage' )
|
{(fileName && fileName !== '' && fileName !== 'noImage' )
|
||||||
? ( <Avatar backgroundColor='#ffffff' src={fileName} size={size || 36} style={style} onTouchTap={onTouchTap} />)
|
? ( <Avatar src={fileName ? fileName : ' '} style={{...style, backgroundColor: '#ffffff', width: size || 36, height: size || 36}} onClick={onClick} />)
|
||||||
: (<Avatar backgroundColor='#00bcd4' size={size || 36} style={style} onTouchTap={onTouchTap}>{fullName ? fullName.slice(0, 1) : ''}</Avatar>) }
|
: (<Avatar style={{...style, backgroundColor: '#00bcd4', width: size || 36, height: size || 36}} onClick={onClick}>{fullName ? fullName.slice(0, 1) : ''}</Avatar>) }
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,4 +155,9 @@ export interface IUserBoxComponentProps {
|
|||||||
* Whether the select circles box for referer user is open
|
* Whether the select circles box for referer user is open
|
||||||
*/
|
*/
|
||||||
isSelecteCirclesOpen?: boolean
|
isSelecteCirclesOpen?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles
|
||||||
|
*/
|
||||||
|
classes?: any
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,17 +5,25 @@ import { connect } from 'react-redux'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import Paper from 'material-ui/Paper'
|
import Paper from 'material-ui/Paper'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import RaisedButton from 'material-ui/RaisedButton'
|
import RaisedButton from 'material-ui/Button'
|
||||||
import Popover, { PopoverAnimationVertical } from 'material-ui/Popover'
|
import Menu, { MenuItem } from 'material-ui/Menu'
|
||||||
import Menu from 'material-ui/Menu'
|
|
||||||
import MenuItem from 'material-ui/MenuItem'
|
|
||||||
import Checkbox from 'material-ui/Checkbox'
|
import Checkbox from 'material-ui/Checkbox'
|
||||||
import TextField from 'material-ui/TextField'
|
import TextField from 'material-ui/TextField'
|
||||||
import { Dialog } from 'material-ui'
|
import Tooltip from 'material-ui/Tooltip'
|
||||||
import SvgAdd from 'material-ui/svg-icons/content/add'
|
import { withStyles } from 'material-ui/styles'
|
||||||
|
import List, { ListItem, ListItemSecondaryAction, ListItemText } from 'material-ui/List'
|
||||||
|
import Divider from 'material-ui/Divider'
|
||||||
|
import Dialog, {
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
|
DialogTitle,
|
||||||
|
withMobileDialog
|
||||||
|
} from 'material-ui/Dialog'
|
||||||
|
import SvgAdd from 'material-ui-icons/add'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import { grey400, grey800, darkBlack, lightBlack } from 'material-ui/styles/colors'
|
import { grey } from 'material-ui/colors'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import UserAvatar from 'components/userAvatar'
|
import UserAvatar from 'components/userAvatar'
|
||||||
@@ -34,6 +42,24 @@ import { ServerRequestType } from 'constants/serverRequestType'
|
|||||||
import { ServerRequestStatusType } from 'actions/serverRequestStatusType'
|
import { ServerRequestStatusType } from 'actions/serverRequestStatusType'
|
||||||
import { ServerRequestModel } from 'models/server'
|
import { ServerRequestModel } from 'models/server'
|
||||||
|
|
||||||
|
const styles = (theme: any) => ({
|
||||||
|
root: {
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: 360,
|
||||||
|
backgroundColor: theme.palette.background.paper
|
||||||
|
},
|
||||||
|
dialogContent: {
|
||||||
|
paddingTop: '5px',
|
||||||
|
padding: '0px 5px 5px 5px'
|
||||||
|
},
|
||||||
|
circleName: {
|
||||||
|
fontSize: '1rem'
|
||||||
|
},
|
||||||
|
space: {
|
||||||
|
height: 20
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
*/
|
*/
|
||||||
@@ -81,7 +107,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
|||||||
*/
|
*/
|
||||||
constructor (props: IUserBoxComponentProps) {
|
constructor (props: IUserBoxComponentProps) {
|
||||||
super(props)
|
super(props)
|
||||||
const { userBelongCircles, circles,userId } = this.props
|
const { userBelongCircles, circles, userId } = this.props
|
||||||
// Defaul state
|
// Defaul state
|
||||||
this.state = {
|
this.state = {
|
||||||
/**
|
/**
|
||||||
@@ -114,9 +140,9 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
|||||||
* Handle follow user
|
* Handle follow user
|
||||||
*/
|
*/
|
||||||
handleDoneAddCircle = () => {
|
handleDoneAddCircle = () => {
|
||||||
const { userId, user , addUserToCircle, selectedCircles, deleteFollowingUser} = this.props
|
const { userId, user, addUserToCircle, selectedCircles, deleteFollowingUser } = this.props
|
||||||
const { avatar, fullName } = user
|
const { avatar, fullName } = user
|
||||||
const {disabledDoneCircles} = this.state
|
const { disabledDoneCircles } = this.state
|
||||||
if (!disabledDoneCircles) {
|
if (!disabledDoneCircles) {
|
||||||
if (selectedCircles!.length > 0) {
|
if (selectedCircles!.length > 0) {
|
||||||
addUserToCircle!(selectedCircles!, { avatar, userId, fullName })
|
addUserToCircle!(selectedCircles!, { avatar, userId, fullName })
|
||||||
@@ -132,7 +158,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
|||||||
onFollowUser = (event: any) => {
|
onFollowUser = (event: any) => {
|
||||||
// This prevents ghost click
|
// This prevents ghost click
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const {isFollowed, followUser, followingCircleId, userId, user, followRequest } = this.props
|
const { isFollowed, followUser, followingCircleId, userId, user, followRequest } = this.props
|
||||||
|
|
||||||
if (followRequest && followRequest.status === ServerRequestStatusType.Sent) {
|
if (followRequest && followRequest.status === ServerRequestStatusType.Sent) {
|
||||||
return
|
return
|
||||||
@@ -149,7 +175,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
|||||||
* Handle request close for add circle box
|
* Handle request close for add circle box
|
||||||
*/
|
*/
|
||||||
onRequestCloseAddCircle = () => {
|
onRequestCloseAddCircle = () => {
|
||||||
const {setSelectedCircles, userId, userBelongCircles, closeSelectCircles} = this.props
|
const { setSelectedCircles, userId, userBelongCircles, closeSelectCircles } = this.props
|
||||||
setSelectedCircles!(userId, userBelongCircles!)
|
setSelectedCircles!(userId, userBelongCircles!)
|
||||||
closeSelectCircles!(userId)
|
closeSelectCircles!(userId)
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -164,7 +190,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
|||||||
* Handle request open for add circle box
|
* Handle request open for add circle box
|
||||||
*/
|
*/
|
||||||
onRequestOpenAddCircle = () => {
|
onRequestOpenAddCircle = () => {
|
||||||
const { openSelectCircles, userId} = this.props
|
const { openSelectCircles, userId } = this.props
|
||||||
openSelectCircles!(userId)
|
openSelectCircles!(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +244,7 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
|||||||
* Create a circle list of user which belong to
|
* Create a circle list of user which belong to
|
||||||
*/
|
*/
|
||||||
circleList = () => {
|
circleList = () => {
|
||||||
let { circles, userId, userBelongCircles, selectedCircles } = this.props
|
let { circles, userId, userBelongCircles, selectedCircles, classes } = this.props
|
||||||
|
|
||||||
if (circles) {
|
if (circles) {
|
||||||
|
|
||||||
@@ -226,19 +252,16 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
|||||||
let isBelong = selectedCircles ? selectedCircles!.indexOf(circleId) > -1 : false
|
let isBelong = selectedCircles ? selectedCircles!.indexOf(circleId) > -1 : false
|
||||||
|
|
||||||
// Create checkbox for selected/unselected circle
|
// Create checkbox for selected/unselected circle
|
||||||
return <Checkbox
|
return (
|
||||||
key={`${circleId}-${userId}`}
|
<ListItem key={`${circleId}-${userId}`} dense className={classes.listItem}>
|
||||||
style={{ padding: '10px' }}
|
<ListItemText className={classes.circleName} primary={circles![circleId].name} />
|
||||||
label={circles![circleId].name}
|
<ListItemSecondaryAction>
|
||||||
labelStyle={{
|
<Checkbox
|
||||||
overflow: 'hidden',
|
onChange={(event: object, isInputChecked: boolean) => this.handleSelectCircle(event, isInputChecked, circleId)}
|
||||||
textOverflow: 'ellipsis',
|
checked={isBelong}
|
||||||
whiteSpace: 'nowrap',
|
/>
|
||||||
width: '100%'
|
</ListItemSecondaryAction>
|
||||||
}}
|
</ListItem>)
|
||||||
onCheck={(event: object, isInputChecked: boolean) => this.handleSelectCircle(event, isInputChecked, circleId)}
|
|
||||||
checked={isBelong}
|
|
||||||
/>
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return parsedDate
|
return parsedDate
|
||||||
@@ -271,28 +294,11 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
|||||||
* @return {react element} return the DOM which rendered by component
|
* @return {react element} return the DOM which rendered by component
|
||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
const {disabledDoneCircles} = this.state
|
const { disabledDoneCircles } = this.state
|
||||||
const { isFollowed, followRequest, userId, isSelecteCirclesOpen, addToCircleRequest, deleteFollowingUserRequest } = this.props
|
const { isFollowed, followRequest, userId, isSelecteCirclesOpen, addToCircleRequest, deleteFollowingUserRequest, classes } = this.props
|
||||||
const writeActions = [
|
|
||||||
<FlatButton
|
|
||||||
label='Cancel'
|
|
||||||
primary={true}
|
|
||||||
keyboardFocused={false}
|
|
||||||
onTouchTap={this.onRequestCloseAddCircle}
|
|
||||||
style={{ color: grey800 }}
|
|
||||||
/>,
|
|
||||||
<FlatButton
|
|
||||||
label='Done'
|
|
||||||
primary={true}
|
|
||||||
keyboardFocused={false}
|
|
||||||
disabled={disabledDoneCircles || (addToCircleRequest ? addToCircleRequest!.status === ServerRequestStatusType.Sent : false)}
|
|
||||||
onTouchTap={this.handleDoneAddCircle}
|
|
||||||
/>
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper key={userId} style={this.styles.paper} zDepth={1} className='grid-cell'>
|
<Paper key={userId} style={this.styles.paper} elevation={1} className='grid-cell'>
|
||||||
<div style={{
|
<div style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@@ -316,54 +322,69 @@ export class UserBoxComponent extends Component<IUserBoxComponentProps, IUserBox
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={this.styles.followButton as any}>
|
<div style={this.styles.followButton as any}>
|
||||||
<FlatButton
|
<Button
|
||||||
label={!isFollowed ? 'Follow'
|
color='primary'
|
||||||
: (this.props.belongCirclesCount! > 1 ? `${this.props.belongCirclesCount} Circles` : ((this.props.firstBelongCircle) ? this.props.firstBelongCircle.name : 'Follow'))}
|
onClick={this.onFollowUser}
|
||||||
primary={true}
|
|
||||||
onTouchTap={this.onFollowUser}
|
|
||||||
disabled={
|
disabled={
|
||||||
(followRequest ? followRequest.status === ServerRequestStatusType.Sent : false) ||
|
(followRequest ? followRequest.status === ServerRequestStatusType.Sent : false) ||
|
||||||
(deleteFollowingUserRequest ? deleteFollowingUserRequest.status === ServerRequestStatusType.Sent : false)
|
(deleteFollowingUserRequest ? deleteFollowingUserRequest.status === ServerRequestStatusType.Sent : false)
|
||||||
}
|
}
|
||||||
/>
|
>
|
||||||
|
{!isFollowed ? 'Follow'
|
||||||
|
: (this.props.belongCirclesCount! > 1 ? `${this.props.belongCirclesCount} Circles` : ((this.props.firstBelongCircle) ? this.props.firstBelongCircle.name : 'Follow'))}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Dialog
|
<Dialog
|
||||||
key={this.props.userId || 0}
|
key={this.props.userId || 0}
|
||||||
actions={writeActions}
|
|
||||||
modal={false}
|
|
||||||
open={isSelecteCirclesOpen === true}
|
open={isSelecteCirclesOpen === true}
|
||||||
contentStyle={this.styles.dialog}
|
onClose={this.onRequestCloseAddCircle}
|
||||||
onRequestClose={this.onRequestCloseAddCircle}
|
|
||||||
overlayStyle={{ background: 'rgba(0,0,0,0.12)' }}
|
|
||||||
bodyStyle={{ padding: 0 }}
|
|
||||||
autoDetectWindowHeight={false}
|
|
||||||
actionsContainerStyle={{ borderTop: '1px solid rgb(224, 224, 224)' }}
|
|
||||||
|
|
||||||
>
|
>
|
||||||
<div style={{
|
<DialogContent className={classes.dialogContent}>
|
||||||
position: 'relative',
|
<List>
|
||||||
display: 'block',
|
|
||||||
maxHeight: '220px'
|
|
||||||
}}>
|
|
||||||
<div style={{ overflowY: 'auto', height: '100%' }}>
|
|
||||||
{this.circleList()}
|
{this.circleList()}
|
||||||
|
<div className={classes.space}></div>
|
||||||
</div>
|
<Divider />
|
||||||
</div>
|
<ListItem key={`'circleName'-${userId}`} dense className={classes.listItem}>
|
||||||
<div style={{ padding: '10px' }}>
|
<ListItemText primary={
|
||||||
<TextField
|
<TextField
|
||||||
hintText='Group name'
|
autoFocus
|
||||||
onChange={this.handleChangeName}
|
placeholder='Group name'
|
||||||
value={this.state.circleName}
|
onChange={this.handleChangeName}
|
||||||
/>
|
value={this.state.circleName}
|
||||||
<div className='user-box__add-circle'>
|
/>
|
||||||
<IconButton onClick={this.onCreateCircle} tooltip='Create circle' disabled={this.state.disabledCreateCircle}>
|
} />
|
||||||
<SvgAdd />
|
<ListItemSecondaryAction>
|
||||||
</IconButton>
|
<IconButton onClick={this.onCreateCircle} disabled={this.state.disabledCreateCircle}>
|
||||||
</div>
|
<Tooltip title='Create circle'>
|
||||||
<br />
|
<SvgAdd />
|
||||||
</div>
|
</Tooltip>
|
||||||
|
</IconButton>
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
color='primary'
|
||||||
|
disableFocusRipple={true}
|
||||||
|
disableRipple={true}
|
||||||
|
onClick={this.onRequestCloseAddCircle}
|
||||||
|
style={{ color: grey[800] }}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
color='primary'
|
||||||
|
disableFocusRipple={true}
|
||||||
|
disableRipple={true}
|
||||||
|
disabled={disabledDoneCircles || (addToCircleRequest ? addToCircleRequest!.status === ServerRequestStatusType.Sent : false)}
|
||||||
|
onClick={this.handleDoneAddCircle}
|
||||||
|
>
|
||||||
|
Done
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
@@ -407,7 +428,7 @@ const mapStateToProps = (state: any, ownProps: IUserBoxComponentProps) => {
|
|||||||
const userBelongCircles = circle ? (circle.userTies[ownProps.userId] ? circle.userTies[ownProps.userId].circleIdList : []) : []
|
const userBelongCircles = circle ? (circle.userTies[ownProps.userId] ? circle.userTies[ownProps.userId].circleIdList : []) : []
|
||||||
const isFollowed = userBelongCircles.length > 0
|
const isFollowed = userBelongCircles.length > 0
|
||||||
const followingCircleId = circles ? Object.keys(circles)
|
const followingCircleId = circles ? Object.keys(circles)
|
||||||
.filter((circleId) => circles[circleId].isSystem && circles[circleId].name === `Following`)[0] : ''
|
.filter((circleId) => circles[circleId].isSystem && circles[circleId].name === `Following`)[0] : ''
|
||||||
const followRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleFollowUser, ownProps.userId)] : null
|
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 addToCircleRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleAddToCircle, ownProps.userId)] : null
|
||||||
const deleteFollowingUserRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleDeleteFollowingUser, ownProps.userId)] : null
|
const deleteFollowingUserRequest: ServerRequestModel = request ? request[StringAPI.createServerRequestId(ServerRequestType.CircleDeleteFollowingUser, ownProps.userId)] : null
|
||||||
@@ -430,4 +451,4 @@ const mapStateToProps = (state: any, ownProps: IUserBoxComponentProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - Connect component to redux store
|
// - Connect component to redux store
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UserBoxComponent as any)
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(UserBoxComponent as any) as any)
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { List } from 'material-ui/List'
|
import List from 'material-ui/List'
|
||||||
|
|
||||||
// - Import app components
|
// - Import app components
|
||||||
import CircleComponent from 'components/circle'
|
import CircleComponent from 'components/circle'
|
||||||
import { IYourCirclesComponentProps } from './IYourCirclesComponentProps'
|
import { IYourCirclesComponentProps } from './IYourCirclesComponentProps'
|
||||||
import { IYourCirclesComponentState } from './IYourCirclesComponentState'
|
import { IYourCirclesComponentState } from './IYourCirclesComponentState'
|
||||||
import { Circle } from 'core/domain/circles';
|
import { Circle } from 'core/domain/circles'
|
||||||
|
|
||||||
// - Import API
|
// - Import API
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ export class YourCirclesComponent extends Component<IYourCirclesComponentProps,I
|
|||||||
|
|
||||||
if (circles) {
|
if (circles) {
|
||||||
Object.keys(circles).map((key, index) => {
|
Object.keys(circles).map((key, index) => {
|
||||||
parsedCircles.push(<CircleComponent key={key} circle={circles![key]} id={key} uid={uid!} />)
|
parsedCircles.push(<CircleComponent key={key} circle={circles![key]} id={key} uid={uid!} />)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return parsedCircles
|
return parsedCircles
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export enum ServerRequestType {
|
|||||||
CircleFollowUser = 'CircleFollowUser',
|
CircleFollowUser = 'CircleFollowUser',
|
||||||
CircleCreateTieUser = 'CircleCreateTieUser',
|
CircleCreateTieUser = 'CircleCreateTieUser',
|
||||||
CircleDeleteFollowingUser = 'CircleDeleteFollowingUser',
|
CircleDeleteFollowingUser = 'CircleDeleteFollowingUser',
|
||||||
CommonSendFeedback = 'CommonSendFeedback'
|
CommonSendFeedback = 'CommonSendFeedback',
|
||||||
|
CommentGetComments = 'CommentGetComments'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export enum FeedType {
|
export enum FeedType {
|
||||||
Awesome = 'Awesome',
|
Awesome = 'Awesome',
|
||||||
Happy = 'Happey',
|
Happy = 'Happy',
|
||||||
Acceptable = 'Acceptable',
|
Acceptable = 'Acceptable',
|
||||||
Sad = 'Sad',
|
Sad = 'Sad',
|
||||||
Bug = 'Bug'
|
Bug = 'Bug'
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ export class GraphService implements IGraphService {
|
|||||||
graphsRef = graphsRef.where('leftNode', '==', leftNode)
|
graphsRef = graphsRef.where('leftNode', '==', leftNode)
|
||||||
}
|
}
|
||||||
if (rightNode && rightNode != null) {
|
if (rightNode && rightNode != null) {
|
||||||
console.trace('getGraphsQuery', {collection, leftNode, edgeType, rightNode})
|
|
||||||
|
|
||||||
graphsRef = graphsRef.where('rightNode', '==', rightNode)
|
graphsRef = graphsRef.where('rightNode', '==', rightNode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,9 @@ import React from 'react'
|
|||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import { AppContainer } from 'react-hot-loader'
|
import { AppContainer } from 'react-hot-loader'
|
||||||
import injectTapEventPlugin from 'react-tap-event-plugin'
|
import injectTapEventPlugin from 'react-tap-event-plugin'
|
||||||
import { cyan500 } from 'material-ui/styles/colors'
|
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles'
|
||||||
import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme'
|
|
||||||
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
|
|
||||||
import getMuiTheme from 'material-ui/styles/getMuiTheme'
|
|
||||||
import 'reflect-metadata'
|
import 'reflect-metadata'
|
||||||
|
import 'typeface-roboto'
|
||||||
|
|
||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import store, { history } from 'store/configureStore'
|
import store, { history } from 'store/configureStore'
|
||||||
@@ -21,31 +19,16 @@ import Master from 'components/master'
|
|||||||
// tslint:disable-next-line:no-empty
|
// tslint:disable-next-line:no-empty
|
||||||
store.subscribe(() => { })
|
store.subscribe(() => { })
|
||||||
|
|
||||||
// Needed for onTouchTap
|
// Needed for onClick
|
||||||
// http://stackoverflow.com/a/34015469/988941
|
// http://stackoverflow.com/a/34015469/988941
|
||||||
try { injectTapEventPlugin() } catch (e) { }
|
try { injectTapEventPlugin() } catch (e) { }
|
||||||
|
|
||||||
// This replaces the textColor value on the palette
|
const theme = createMuiTheme({
|
||||||
// and then update the keys for each component that depends on it.
|
|
||||||
// More on Colors: http://www.material-ui.com/#/customization/colors
|
|
||||||
const muiTheme = getMuiTheme({
|
|
||||||
palette: {
|
palette: {
|
||||||
primary1Color: 'rgb(199, 212, 0)'
|
primary: { main: '#00b1b3' },
|
||||||
},
|
secondary: { main: '#4d545d' }
|
||||||
// raisedButton: {
|
|
||||||
// primaryColor: 'rgb(199, 212, 0)' // Raised button background color
|
|
||||||
// },
|
|
||||||
// flatButton: {
|
|
||||||
// primaryTextColor: 'rgb(199, 212, 0)' // Flat button background color
|
|
||||||
// },
|
|
||||||
// tabs: {
|
|
||||||
// backgroundColor: 'rgb(199, 212, 0)' // Tabs backgound color
|
|
||||||
// },
|
|
||||||
toolbar: {
|
|
||||||
backgroundColor: '#6d9828' // Backgroung color of header in toolbar
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// App css
|
// App css
|
||||||
import 'applicationStyles'
|
import 'applicationStyles'
|
||||||
|
|
||||||
@@ -60,7 +43,7 @@ const render = (Component: any) => {
|
|||||||
<AppContainer warnings={false}>
|
<AppContainer warnings={false}>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<ConnectedRouter history={history}>
|
<ConnectedRouter history={history}>
|
||||||
<MuiThemeProvider muiTheme={muiTheme}>
|
<MuiThemeProvider theme={theme}>
|
||||||
<Component />
|
<Component />
|
||||||
</MuiThemeProvider>
|
</MuiThemeProvider>
|
||||||
</ConnectedRouter>
|
</ConnectedRouter>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// - Import react components
|
// - Import react components
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { grey400 } from 'material-ui/styles/colors'
|
import { grey } from 'material-ui/colors'
|
||||||
import SvgClose from 'material-ui/svg-icons/navigation/close'
|
import SvgClose from 'material-ui-icons/close'
|
||||||
import FlatButton from 'material-ui/FlatButton'
|
import Button from 'material-ui/Button'
|
||||||
import Divider from 'material-ui/Divider'
|
import Divider from 'material-ui/Divider'
|
||||||
import { IDialogTitleComponentProps } from './IDialogTitleComponentProps'
|
import { IDialogTitleComponentProps } from './IDialogTitleComponentProps'
|
||||||
import { IDialogTitleComponentState } from './IDialogTitleComponentState'
|
import { IDialogTitleComponentState } from './IDialogTitleComponentState'
|
||||||
@@ -76,13 +76,13 @@ export default class DialogTitleComponent extends Component<IDialogTitleComponen
|
|||||||
<div className='g__dialog-title'>
|
<div className='g__dialog-title'>
|
||||||
<div style={this.styles.contain as any}>
|
<div style={this.styles.contain as any}>
|
||||||
<div style={{ paddingRight: '10px' }}>
|
<div style={{ paddingRight: '10px' }}>
|
||||||
<SvgClose onClick={onRequestClose} hoverColor={grey400} style={{ cursor: 'pointer' }} />
|
<SvgClose onClick={onRequestClose} hoverColor={grey[400]} style={{ cursor: 'pointer' }} />
|
||||||
</div>
|
</div>
|
||||||
<div style={this.styles.title}>
|
<div style={this.styles.title}>
|
||||||
{title || ''}
|
{title || ''}
|
||||||
</div>
|
</div>
|
||||||
{ buttonLabel ? (<div style={{ marginTop: '-9px' }}>
|
{ buttonLabel ? (<div style={{ marginTop: '-9px' }}>
|
||||||
<FlatButton label={buttonLabel || ''} primary={true} disabled={disabledButton ? disabledButton : false} onClick={onClickButton || (x => x)} />
|
<Button label={buttonLabel || ''} color='primary' disabled={disabledButton ? disabledButton : false} onClick={onClickButton || (x => x)} />
|
||||||
</div>) : ''}
|
</div>) : ''}
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// - Import react components
|
// - Import react components
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import IconButton from 'material-ui/IconButton'
|
import IconButton from 'material-ui/IconButton'
|
||||||
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'
|
import MoreVertIcon from 'material-ui-icons/moreVert'
|
||||||
import { grey200, grey400, grey600 } from 'material-ui/styles/colors'
|
import { grey } from 'material-ui/colors'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOM styles
|
* DOM styles
|
||||||
@@ -11,18 +11,9 @@ import { grey200, grey400, grey600 } from 'material-ui/styles/colors'
|
|||||||
* @memberof Post
|
* @memberof Post
|
||||||
*/
|
*/
|
||||||
const styles = {
|
const styles = {
|
||||||
iconButton: {
|
|
||||||
width: 24,
|
|
||||||
height: 24
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// TODO: Delete the component
|
||||||
const IconButtonElementComponent = (
|
const IconButtonElementComponent = (<div> </div>)
|
||||||
<IconButton style={styles.iconButton} iconStyle={styles.iconButton}
|
|
||||||
touch={true}
|
|
||||||
>
|
|
||||||
<MoreVertIcon color={grey400} viewBox='9 0 24 24' />
|
|
||||||
</IconButton>
|
|
||||||
)
|
|
||||||
|
|
||||||
export default IconButtonElementComponent
|
export default IconButtonElementComponent
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// - Import react components
|
// - Import react components
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { grey400, grey800, darkBlack, lightBlack,tealA400 } from 'material-ui/styles/colors'
|
import { teal } from 'material-ui/colors'
|
||||||
import CircularProgress from 'material-ui/CircularProgress'
|
import { CircularProgress } from 'material-ui/Progress'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create component class
|
* Create component class
|
||||||
@@ -14,7 +14,7 @@ export default class LoadMoreProgressComponent extends Component<{},{}> {
|
|||||||
*/
|
*/
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className='g-load-more'><CircularProgress size={30} thickness={5} color={tealA400} /></div>
|
<div className='g-load-more'><CircularProgress size={30} thickness={5} style={{color: teal['A400'] }} /></div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,4 +52,9 @@ export class CircleState {
|
|||||||
* @memberof CircleState
|
* @memberof CircleState
|
||||||
*/
|
*/
|
||||||
loaded: boolean = false
|
loaded: boolean = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Circle stting state
|
||||||
|
*/
|
||||||
|
openSetting: {[circleId: string]: boolean }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,11 +37,14 @@ export let circleReducer = (state: CircleState = new CircleState(), action: ICir
|
|||||||
case CircleActionType.UPDATE_CIRCLE:
|
case CircleActionType.UPDATE_CIRCLE:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
openSetting: {
|
||||||
|
...state.openSetting,
|
||||||
|
[payload.circle.id]: false
|
||||||
|
},
|
||||||
circleList: {
|
circleList: {
|
||||||
...state.circleList,
|
...state.circleList,
|
||||||
[payload.circle.id]: {
|
[payload.circle.id]: {
|
||||||
...payload.circle,
|
...payload.circle
|
||||||
openCircleSettings: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,24 +159,18 @@ export let circleReducer = (state: CircleState = new CircleState(), action: ICir
|
|||||||
case CircleActionType.CLOSE_CIRCLE_SETTINGS:
|
case CircleActionType.CLOSE_CIRCLE_SETTINGS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
circleList: {
|
openSetting: {
|
||||||
...state.circleList,
|
...state.openSetting,
|
||||||
[payload.circleId]: {
|
[payload.circleId]: false
|
||||||
...state.circleList[payload.circleId],
|
|
||||||
openCircleSettings: false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case CircleActionType.OPEN_CIRCLE_SETTINGS:
|
case CircleActionType.OPEN_CIRCLE_SETTINGS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
circleList: {
|
openSetting: {
|
||||||
...state.circleList,
|
...state.openSetting,
|
||||||
[payload.circleId]: {
|
[payload.circleId]: true
|
||||||
...state.circleList[payload.circleId],
|
|
||||||
openCircleSettings: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export let commentReducer = (state: CommentState = new CommentState(), action: I
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
postComments: {
|
postComments: {
|
||||||
|
...state.postComments,
|
||||||
...payload
|
...payload
|
||||||
},
|
},
|
||||||
loaded: true
|
loaded: true
|
||||||
|
|||||||
@@ -200,4 +200,13 @@ input[type="file"] {
|
|||||||
width: 76px;
|
width: 76px;
|
||||||
margin: 3px auto 15px;
|
margin: 3px auto 15px;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
g__input-underline {
|
||||||
|
&::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
.homeHeader__page {
|
.homeHeader__title-root {
|
||||||
border-left: 1px solid rgba(255, 255, 255, 0.2);
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.homeHeader__title {
|
||||||
|
border-left: 1px solid #fff;
|
||||||
padding-left: 24px;
|
padding-left: 24px;
|
||||||
margin-left: 24px;
|
margin-left: 24px;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
@@ -7,7 +11,7 @@
|
|||||||
font-family: Roboto, RobotoDraft, Helvetica, Arial, sans-serif;
|
font-family: Roboto, RobotoDraft, Helvetica, Arial, sans-serif;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
color: white;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.homeHeader__right {
|
.homeHeader__right {
|
||||||
|
|||||||
@@ -11,7 +11,12 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.main-box {
|
||||||
|
padding: 26px 26px 0px 26px;
|
||||||
|
}
|
||||||
.buttons {
|
.buttons {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-left: 50px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.close {
|
.close {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
.signup__button-box{
|
.signup__button-box{
|
||||||
@extend .login__button-box
|
margin-top: 30px;
|
||||||
|
@extend .login__button-box;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user