// - Import react components import React, { Component } from 'react' import { connect } from 'react-redux' import PropTypes from 'prop-types' 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, { 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 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' import Img from 'components/img' import UserAvatarComponent from 'components/userAvatar' // - Import API import * as PostAPI from 'api/PostAPI' // - Import actions import * as imageGalleryActions from 'actions/imageGalleryActions' import * as postActions from 'actions/postActions' 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 { /** * Component constructor * @param {object} props is an object properties of component */ constructor (props: IPostWriteComponentProps) { super(props) const { postModel } = props // Default state this.state = { /** * 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, /** * Whether menu is open */ menuOpen: false, /** * If it's true post button will be disabled */ disabledPost: true, /** * If it's true comment will be disabled on post */ disableComments: this.props.edit && postModel ? postModel.disableComments! : false, /** * If it's true share will be disabled on post */ disableSharing: this.props.edit && postModel ? postModel.disableSharing! : false } // Binding functions to `this` this.handleOnChange = this.handleOnChange.bind(this) this.handleCloseGallery = this.handleCloseGallery.bind(this) this.handleOpenGallery = this.handleOpenGallery.bind(this) this.onRequestSetImage = this.onRequestSetImage.bind(this) this.handlePost = this.handlePost.bind(this) this.handleRemoveImage = this.handleRemoveImage.bind(this) this.handleToggleComments = this.handleToggleComments.bind(this) this.handleToggleSharing = this.handleToggleSharing.bind(this) } /** * Toggle comments of the post to disable/enable * * * @memberof PostWrite */ handleToggleComments = () => { this.setState({ disableComments: !this.state.disableComments, disabledPost: false }) } /** * Toggle sharing of the post to disable/enable * * * @memberof PostWrite */ handleToggleSharing = () => { this.setState({ disableSharing: !this.state.disableSharing, disabledPost: false }) } /** * Romove the image of post * * * @memberof PostWrite */ handleRemoveImage = () => { this.setState({ image: '', imageFullPath: '', disabledPost: this.state.postText.trim() === '' }) } /** * Handle send post to the server * @param {event} evt passed by clicking on the post button */ handlePost = () => { const { image, imageFullPath, disableComments, disableSharing, postText } = this.state const { id, ownerAvatar, ownerDisplayName, edit, onRequestClose, post, update, postModel } = this.props if (image === '' && postText.trim() === '') { this.setState({ disabledPost: false }) return } let tags = PostAPI.getContentTags(postText!) // In edit status we should fire update if not we should fire post function if (!edit) { if (image !== '') { post!({ body: postText, tags: tags, image: image, imageFullPath: imageFullPath, ownerAvatar: ownerAvatar, ownerDisplayName: ownerDisplayName, disableComments: disableComments, disableSharing: disableSharing, postTypeId: 1, score: 0, viewCount: 0 }, onRequestClose) } else { post!({ body: postText, tags: tags, ownerAvatar: ownerAvatar, ownerDisplayName: ownerDisplayName, disableComments: disableComments, disableSharing: disableSharing, postTypeId: 0, score: 0, viewCount: 0 }, onRequestClose) } } else { // In edit status we pass post to update functions postModel!.body = postText postModel!.tags = tags postModel!.image = image postModel!.imageFullPath = imageFullPath postModel!.disableComments = disableComments postModel!.disableSharing = disableSharing update!(postModel!, onRequestClose) } } /** * Set post image url */ onRequestSetImage = (url: string, fullPath: string) => { this.setState({ image: url, imageFullPath: fullPath, disabledPost: false }) } /** * When the post text changed * @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) => { 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({ postText: data, disabledPost: true }) } else { this.setState({ postText: data, disabledPost: false }) } } /** * Close image gallery */ handleCloseGallery = () => { this.setState({ galleryOpen: false }) } /** * Open image gallery */ handleOpenGallery = () => { this.setState({ galleryOpen: true }) } /** * 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 this.setState({ /** * Post text */ postText: this.props.edit && postModel ? (postModel.body ? postModel.body! : '') : '', /** * The URL image of the post */ image: this.props.edit && postModel ? (postModel.image ? postModel.image! : '') : '', /** * The path identifier of image on the server */ imageFullPath: this.props.edit && postModel ? (postModel.imageFullPath ? postModel.imageFullPath! : '') : '', /** * If it's true gallery will be open */ galleryOpen: false, /** * If it's true post button will be disabled */ disabledPost: true, /** * If it's true comment will be disabled on post */ disableComments: this.props.edit && postModel ? postModel.disableComments! : false, /** * If it's true share will be disabled on post */ disableSharing: this.props.edit && postModel ? postModel.disableSharing! : false }) } } /** * Reneder component DOM * @return {react element} return the DOM which rendered by component */ render () { const { classes } = this.props const { menuOpen } = this.state const rightIconMenu = ( {!this.state.disableComments ? 'Disable comments' : 'Enable comments'} {!this.state.disableSharing ? 'Disable sharing' : 'Enable sharing'} ) let postAvatar = let author = (
{this.props.ownerDisplayName} | Public
) /** * Provide post image */ const loadImage = (this.state.image && this.state.image !== '') ? (
) : '' const styles = { dialog: { width: '', maxWidth: '530px', borderRadius: '4px' } } return (
{this.props.children}
{loadImage}
) } } /** * 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: any, ownProps: IPostWriteComponentProps) => { return { post: (post: Post, callBack: Function) => dispatch(postActions.dbAddImagePost(post, callBack)), update: (post: Post, callBack: Function) => dispatch(postActions.dbUpdatePost(post, callBack)) } } /** * Map state to props * @param {object} state is the obeject from redux store * @param {object} ownProps is the props belong to component * @return {object} props of component */ const mapStateToProps = (state: any, ownProps: IPostWriteComponentProps) => { return { postImageState: state.imageGallery.status, ownerAvatar: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].avatar : '', ownerDisplayName: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].fullName : '' } } // - Connect component to redux store export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles as any)(PostWriteComponent as any) as any)