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