249 lines
7.1 KiB
JavaScript
249 lines
7.1 KiB
JavaScript
// - Impoer react components
|
|
import React, { Component } from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import { connect } from 'react-redux'
|
|
import { GridList, GridTile } 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 uuid from 'uuid'
|
|
|
|
|
|
// - Import actions
|
|
import * as imageGalleryActions from 'imageGalleryActions'
|
|
import * as globalActions from 'globalActions'
|
|
|
|
// - Import app components
|
|
import Img from 'Img'
|
|
|
|
// - Import API
|
|
import FileAPI from 'FileAPI'
|
|
|
|
/**
|
|
* Create ImageGallery component class
|
|
*/
|
|
export class ImageGallery extends Component {
|
|
|
|
static propTypes = {
|
|
|
|
/**
|
|
* Callback function to ser image url on parent component
|
|
*/
|
|
open: PropTypes.func
|
|
}
|
|
|
|
/**
|
|
* Component constructor
|
|
* @param {object} props is an object properties of component
|
|
*/
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
// Binding function to `this`
|
|
this.close = this.close.bind(this)
|
|
this.onFileChange = this.onFileChange.bind(this)
|
|
this.handleSetImage = this.handleSetImage.bind(this)
|
|
this.handleDeleteImage = this.handleDeleteImage.bind(this)
|
|
this.imageList = this.imageList.bind(this)
|
|
}
|
|
|
|
/**
|
|
* Handle set image
|
|
* @param {event} evt passed by on click event on add image
|
|
* @param {string} name is the name of the image
|
|
*/
|
|
handleSetImage = (evt, URL,fullPath) => {
|
|
this.props.set(URL,fullPath)
|
|
this.close()
|
|
}
|
|
|
|
/**
|
|
* Handle delete image
|
|
* @param {event} evt passed by on click event on delete image
|
|
* @param {integer} id is the image identifier which selected to delete
|
|
*/
|
|
handleDeleteImage = (evt, id) => {
|
|
this.props.deleteImage(id)
|
|
}
|
|
|
|
componentDidMount() {
|
|
window.addEventListener("onSendResizedImage", this.handleSendResizedImage)
|
|
}
|
|
componentWillUnmount() {
|
|
window.removeEventListener("onSendResizedImage", this.handleSendResizedImage)
|
|
}
|
|
|
|
/**
|
|
* Handle send image resize event that pass the resized image
|
|
*
|
|
*
|
|
* @memberof ImageGallery
|
|
*/
|
|
handleSendResizedImage = (event) => {
|
|
|
|
const { resizedImage, fileName } = event.detail
|
|
const {saveImageGallery, progressChange} = this.props
|
|
|
|
FileAPI.uploadImage(resizedImage, fileName, (percent, status) => {
|
|
progressChange(percent,status)
|
|
}).then((result) => {
|
|
|
|
/* Add image to image gallery */
|
|
saveImageGallery(result.downloadURL,result.metadata.fullPath)
|
|
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Handle on change file upload
|
|
*/
|
|
onFileChange = (evt) => {
|
|
|
|
const extension = FileAPI.getExtension(evt.target.files[0].name)
|
|
var fileName = (`${uuid()}.${extension}`)
|
|
let image = FileAPI.constraintImage(evt.target.files[0], fileName)
|
|
|
|
}
|
|
|
|
/**
|
|
* Hide image gallery
|
|
*/
|
|
close = () => {
|
|
this.props.close()
|
|
}
|
|
|
|
imageList = () => {
|
|
|
|
return this.props.images.map((image, index) => {
|
|
|
|
return (<GridTile
|
|
key={image.id}
|
|
title={<SvgDelete hoverColor={grey200} color="white" color="white" style={{ marginLeft: "5px", cursor: "pointer" }} onClick={evt => this.handleDeleteImage(evt, image.id)} />}
|
|
subtitle={<span></span>}
|
|
actionIcon={<SvgAddImage hoverColor={grey200} color="white" style={{ marginRight: "5px", cursor: "pointer" }} onClick={evt => this.handleSetImage(evt, image.URL,image.fullPath)} />}
|
|
>
|
|
<div>
|
|
<div style={{ overflowY: "hidden", overflowX: "auto" }}>
|
|
<ul style={{ whiteSpace: "nowrap", padding: "0 6px", margin: "8px 0 0 0", verticalAlign: "bottom", flexShrink: 0, listStyleType: "none" }}>
|
|
<div style={{ display: "block" }}>
|
|
<div style={{ display: "block", marginRight: "8px", transition: "transform .25s" }}>
|
|
<li style={{ width: "100%", margin: 0, verticalAlign: "bottom", position: "static", display: "inline-block" }}>
|
|
<Img fileName={image.URL} style={{ width: "100%", height: "auto" }} />
|
|
|
|
</li>
|
|
</div>
|
|
</div>
|
|
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</GridTile>)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
render() {
|
|
|
|
|
|
/**
|
|
* Component styles
|
|
* @type {Object}
|
|
*/
|
|
const styles = {
|
|
root: {
|
|
display: 'flex',
|
|
flexWrap: 'wrap',
|
|
justifyContent: 'space-around',
|
|
},
|
|
gridList: {
|
|
width: 500,
|
|
height: 450,
|
|
overflowY: 'auto',
|
|
},
|
|
uploadButton: {
|
|
verticalAlign: 'middle',
|
|
},
|
|
uploadInput: {
|
|
cursor: 'pointer',
|
|
position: 'absolute',
|
|
top: 0,
|
|
bottom: 0,
|
|
right: 0,
|
|
left: 0,
|
|
width: '100%',
|
|
opacity: 0,
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div style={styles.root}>
|
|
<GridList
|
|
cellHeight={180}
|
|
style={styles.gridList}
|
|
>
|
|
<GridTile >
|
|
|
|
<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={styles.uploadButton}
|
|
containerElement="label"
|
|
>
|
|
<input type="file" onChange={this.onFileChange} accept="image/*" style={styles.uploadInput} />
|
|
</FlatButton>
|
|
</div>
|
|
</GridTile>
|
|
{this.imageList()}
|
|
</GridList>
|
|
</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) => {
|
|
return {
|
|
saveImageGallery: (imageURL,imageFullPath) => dispatch(imageGalleryActions.dbSaveImage(imageURL,imageFullPath)),
|
|
deleteImage: (id) => dispatch(imageGalleryActions.dbDeleteImage(id)),
|
|
progressChange : (percent,status) => dispatch(globalActions.progressChange(percent, status))
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 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) => {
|
|
return {
|
|
images: state.imageGallery.images,
|
|
avatar: state.user.info && state.user.info[state.authorize.uid] ? state.user.info[state.authorize.uid].avatar : ''
|
|
|
|
}
|
|
}
|
|
|
|
// - Connect component to redux store
|
|
export default connect(mapStateToProps, mapDispatchToProps)(ImageGallery)
|