app/components/Circle.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { grey400, darkBlack, lightBlack } from 'material-ui/styles/colors';
import { ListItem } from 'material-ui/List';
import SvgGroup from 'material-ui/svg-icons/action/group-work';
import IconMenu from 'material-ui/IconMenu';
import TextField from 'material-ui/TextField';
import MenuItem from 'material-ui/MenuItem';
import IconButtonElement from 'IconButtonElement';
import Dialog from 'material-ui/Dialog';
import Divider from 'material-ui/Divider';
import FlatButton from 'material-ui/FlatButton';
import SvgClose from 'material-ui/svg-icons/navigation/close';
// - Import app components
import UserAvatar from 'UserAvatar';
// - Import actions
import * as circleActions from 'circleActions';
export class Circle extends Component {
/**
* Component constructor
* @param {object} props is an object properties of component
*/
constructor(props) {
super(props);
this.state = {
// If is true circle is open to show users in circle list.
open: false,
// Circle name on change.
circleName: this.props.circle.name,
// Save operation will be disable if user doesn't meet requirement.
disabledSave: false
};
}
/**
* Handle chage circle name
*
* @memberof Circle
*/
handleChangeCircleName = (evt) => {
const { value } = evt.target;
this.setState({
circleName: value,
disabledSave: (!value || value.trim() === '')
});
}
/**
* Update user's circle
*
* @memberof Circle
*/
handleUpdateCircle = () => {
const { circleName } = this.state;
if (circleName && circleName.trim() !== '') {
this.props.updateCircle({ name: circleName, id: this.props.id });
}
}
/**
* Handle delete circle
*
* @memberof Circle
*/
handleDeleteCircle = () => {
this.props.deleteCircle(this.props.id);
}
/**
* Toggle circle to close/open
*
* @memberof Circle
*/
handleToggleCircle = () => {
this.setState({ open: !this.state.open });
}
userList = () => {
const { users } = this.props.circle;
const { userInfo } = this.props;
let usersParsed = [];
if (users) {
Object.keys(users).forEach((key, index) => {
const { fullName } = users[key];
let avatar = userInfo && userInfo[key] ? userInfo[key].avatar || '' : '';
usersParsed.push(<ListItem
key={`${this.props.id}.${key}`}
style={{ backgroundColor: '#e2e2e2' }}
value={2}
primaryText={fullName}
leftAvatar={<UserAvatar fullName={fullName} fileName={avatar} />}
onClick={() => this.props.goTo(`/${key}`)}
/>)
});
return usersParsed;
}
}
/**
* Right icon menue of circle
*
* @memberof Circle
*/
rightIconMenu = (
<IconMenu iconButtonElement={IconButtonElement} style={{ display: "block", position: "absolute", top: "0px", right: "12px" }}>
<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() {
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' }} />
</div>
<div style={{
color: 'rgba(0,0,0,0.87)',
flex: '1 1',
font: '500 20px Roboto,RobotoDraft,Helvetica,Arial,sans-serif'
}}>
Circle settings
</div>
<div style={{ marginTop: '-9px' }}>
<FlatButton label="SAVE" primary={true} disabled={this.state.disabledSave} onClick={this.handleUpdateCircle} />
</div>
</div>
<Divider />
</div>
);
return (
<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={this.rightIconMenu}
initiallyOpen={false}
onClick={this.handleToggleCircle}
open={this.state.open}
nestedItems={this.userList()}
>
<Dialog
id={this.props.id}
title={circleTitle}
modal={false}
open={this.props.openSetting}
onRequestClose={this.props.closeCircleSettings}
overlayStyle={{ background: "rgba(0,0,0,0.12)" }}
contentStyle={{ maxWidth: '400px' }}
>
<div>
<TextField
hintText="Circle name"
floatingLabelText="Circle name"
onChange={this.handleChangeCircleName}
value={this.state.circleName}
/>
</div>
</Dialog>
</ListItem>
</div>
)
}
}
/**
* Map dispatch to props
* @param {func} dispatch is the function to dispatch action to reducers
* @param {object} ownProps is the props belong to component
* @return {object} props of component
*/
const mapDispatchToProps = (dispatch, ownProps) => {
const { uid } = ownProps;
return {
deleteCircle: (id) => dispatch(circleActions.dbDeleteCircle(id)),
updateCircle: (circle) => dispatch(circleActions.dbUpdateCircle(circle)),
closeCircleSettings: () => dispatch(circleActions.closeCircleSettings(uid, ownProps.id)),
openCircleSettings: () => dispatch(circleActions.openCircleSettings(uid, ownProps.id)),
goTo: (url) => dispatch(push(url))
};
}
/**
* Map state to props
* @param {object} state is the obeject from redux store
* @param {object} ownProps is the props belong to component
* @return {object} props of component
*/
const mapStateToProps = (state, ownProps) => {
const { uid } = state.authorize;
return {
openSetting: state.circle ? (state.circle.userCircles[uid] ? (state.circle.userCircles[uid][ownProps.id].openCircleSettings || false) : false) : false,
userInfo: state.user.info
};
}
// - Connect component to redux store
export default connect(mapStateToProps, mapDispatchToProps)(Circle)