diff --git a/client/src/views/common/UploadImage.js b/client/src/views/common/UploadImage.js
index 94a9c9643..9aff6ce47 100644
--- a/client/src/views/common/UploadImage.js
+++ b/client/src/views/common/UploadImage.js
@@ -12,6 +12,7 @@ import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import Button from '@material-ui/core/Button'
+import Typography from '@material-ui/core/Typography'
import MessageCard from './MessageCard'
@@ -36,20 +37,28 @@ const styles = theme => ({
dropzoneText: {
textAlign: 'center'
},
- cropPreview: {
- width: 200,
- height: 200
+ cropAvatarPreview: {
+ width: 100,
+ height: 100
},
- cropBox: {
+ cropBannerPreview: {
+ width: 400,
+ height: 100
+ },
+ cropAvatarBox: {
width: 350,
height: 350
},
+ cropBannerBox: {
+ width: 650,
+ height: 350
+ },
reactCrop: {
}
})
-const imageConfig = {
- quality: 0.5,
+const imageAvatarConfig = {
+ quality: 0.6,
maxWidth: 200,
maxHeight: 200,
autoRotate: true,
@@ -57,6 +66,15 @@ const imageConfig = {
mimeType: 'image/jpeg'
}
+const imageBannerConfig = {
+ quality: 0.6,
+ maxWidth: 800,
+ maxHeight: 200,
+ autoRotate: true,
+ debug: true,
+ mimeType: 'image/jpeg'
+}
+
class UploadImage extends Component {
constructor (props) {
super(props)
@@ -66,10 +84,14 @@ class UploadImage extends Component {
this.handleClickOpen = this.handleClickOpen.bind(this)
this.handleClose = this.handleClose.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
- this.saveAvatar = this.saveAvatar.bind(this)
+ this.handleChangeImage = this.handleChangeImage.bind(this)
+ this.cancelChangeImage = this.cancelChangeImage.bind(this)
+ this.saveImage = this.saveImage.bind(this)
this.state = {
open: false,
+ edit: 'avatar',
+ change: false,
file: null,
src: null,
crop: {
@@ -82,103 +104,147 @@ class UploadImage extends Component {
cropped: null,
rejected: null,
uploaded: false,
- image: ''
+ avatarImage: null,
+ bannerImage: null,
+ sasqr: null
}
}
render () {
- const { classes, team, authId, handleAvatar } = this.props
+ const { classes, team, authId, handleAvatar, handleBanner } = this.props
let avatar = null
- if (team.profile !== null && team.profile.avatar !== undefined && team.profile.avatar !== null && team.profile.avatar !== 'a') {
- avatar = team.profile.avatar
+ let banner = null
+ if ((team.profile !== null && team.profile.avatar !== undefined && team.profile.avatar !== null && team.profile.avatar !== 'a') || this.state.avatarImage !== null) {
+ avatar = this.state.avatarImage !== null ? this.state.avatarImage : `${team.profile.avatar}?${Math.random()}`
} else {
- if (this.state.image !== '') avatar = this.state.image
+ avatar = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EAvatar%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
+ }
+ if ((team.profile !== null && team.profile.banner !== undefined && team.profile.banner !== null && team.profile.banner !== '') || this.state.bannerImage !== null) {
+ banner = this.state.bannerImage !== null ? this.state.bannerImage : `${team.profile.banner}?${Math.random()}`
+ } else {
+ banner = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22800%22%20height%3D%22200%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23banner_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%3E%3Ctitle%3EBanner%20Placeholder%3C%2Ftitle%3E%3Crect%20stroke%3D%22null%22%20id%3D%22svg_1%22%20fill%3D%22%2355595c%22%20height%3D%22200%22%20width%3D%22800%22%2F%3E%3Cg%20stroke%3D%22null%22%20id%3D%22banner_164edaf95ee%22%3E%3Ctext%20stroke%3D%22null%22%20id%3D%22svg_3%22%20y%3D%22106.5%22%20x%3D%22367.73438%22%3EBanner%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
}
- console.log('UploadImage', team, avatar, authId, this.state)
+ let handleImage
+ this.state.edit === 'avatar' ? handleImage = handleAvatar : handleImage = handleBanner
+
+ console.log('UploadImage', team, avatar, banner, authId, this.state)
return (
- {avatar === null && this.state.src === null && (
-
- Drag-and-drop team avater here or click to select files.
Only *.jpeg and *.png images
-
- )}
- {(avatar !== null || this.state.src !== null) && (
-
- {(getAzureSAS, { loading, error, data }) => {
- console.log('getAzureSAS: ', error, data)
- if (!this.state.uploaded) {
- if (data !== undefined && data.getAzureSAS !== null) {
- this.saveAvatar(data.getAzureSAS, team.slug, handleAvatar)
- }
- // this.handleSubmit(getAzureSAS, team.slug)
+
+ {(getAzureSAS, { loading, error, data }) => {
+ console.log('getAzureSAS: ', error, data)
+ if (!this.state.uploaded) {
+ if (data !== undefined && data.getAzureSAS !== null) {
+ this.saveImage(data.getAzureSAS, team.slug, handleImage)
}
- if (this.state.cropping) {
- return (
+ // this.handleSubmit(getAzureSAS, team.slug)
+ }
+ if (this.state.cropping) {
+ return (
+
+
+
+ )
+ } else {
+ return (
+
-
+ {(this.state.change || (avatar === null && banner === null && this.state.src === null)) && (
+
+ this.onDrop(e, this.state.edit)}
+ className={classes.dropzone}
+ multiple={false}
+ >
+ Drag-and-drop team {this.state.edit} here or click to select files.
Only *.jpeg and *.png images
+
+
+
+ )}
+ {!this.state.change && (
+
+
+
+
+ )}
+ {!this.state.change && (
+
+
+
+
+ )}
+ {(this.state.avatarImage !== null || this.state.bannerImage !== null) && (
+
Click Update Team to save image changes!
+ )}
- )
- } else {
- return (
-
-
-

-
-
+
+ )
+ }
+ }}
+
)
}
- onDrop (file) {
+ onDrop (file, editImageType) {
console.log('onDrop', file)
- this.onSelectFile(file)
+ this.onSelectFile(file, editImageType)
this.setState({
file
})
}
- onSelectFile (file) {
+ onSelectFile (file, editImageType) {
if (file && file.length > 0) {
const reader = new window.FileReader()
reader.addEventListener(
@@ -194,53 +260,77 @@ class UploadImage extends Component {
}
}
- async handleCrop (e, getAzureSAS, teamSlug, handleAvatar) {
+ async handleCrop (e, getAzureSAS, teamSlug, handleImage) {
e.preventDefault()
const data = await getAzureSAS({ variables: { teamSlug } })
console.log('handleCrop', this.cropper, data)
const cropped = this.cropper.crop()
const croppedBlob = await imgSrcToBlob(cropped, 'image/png', 'Anonymous')
+ let imageConfig = this.state.edit === 'avatar' ? imageAvatarConfig : imageBannerConfig
let resizedBlob = await readAndCompressImage(croppedBlob, imageConfig)
return this.setState({ cropped: resizedBlob, cropping: true, open: false }, () => {
- this.saveAvatar(data.getAzureSAS, teamSlug, handleAvatar)
+ this.saveImage(data.getAzureSAS, teamSlug, handleImage)
})
}
async handleSubmit (e, getAzureSAS, teamSlug) {
e.preventDefault()
- await getAzureSAS({ variables: { teamSlug } })
+ let SAS = await getAzureSAS({ variables: { teamSlug } })
+ console.log('handleSubmit: ', await SAS)
+ return this.setState({ sasqr: SAS })
}
- async saveAvatar (SASQueryParameters, teamSlug, handleAvatar) {
- const fileName = `${teamSlug}-avatar.jpg`
- console.log('saveAvatar SASurl', process.env.AZURE_SAS_URL)
- const SASurl2 = `${process.env.AZURE_STORAGE_URL}?${SASQueryParameters}`
- const SASurl = process.env.AZURE_SAS_URL
- console.log('getAzureSAS2 SASurl: ', SASurl2, SASurl)
+ async saveImage (SASQueryParameters, teamSlug, handleImage) {
+ const fileName = this.state.edit === 'avatar' ? `${teamSlug}-avatar.jpg` : `${teamSlug}-banner.jpg`
+ let SASurl
+ if (this.state.sasqr === null) {
+ SASurl = process.env.AZURE_SAS_URL
+ } else {
+ SASurl = `${process.env.AZURE_STORAGE_URL}?${this.state.sasqr}`
+ }
+ console.log('getAzureSAS2 SASurl: ', SASurl, this.state.sasqr)
+
const pipeline = Azure.StorageURL.newPipeline(new Azure.AnonymousCredential())
const serviceURL = new Azure.ServiceURL(SASurl, pipeline)
- console.log('getAzureSAS2: ', serviceURL)
+
const containerName = teamSlug
const containerURL = Azure.ContainerURL.fromServiceURL(serviceURL, containerName)
- console.log('getAzureSAS3: ', containerURL)
const blockBlobURL = Azure.BlockBlobURL.fromContainerURL(containerURL, fileName)
- console.log('getAzureSAS34: ', blockBlobURL)
- const avatar = await Azure.uploadBrowserDataToBlockBlob(Azure.Aborter.None, this.state.cropped, blockBlobURL)
- console.log('saveAvatar: ', avatar)
- const image = `${process.env.AZURE_STORAGE_URL}${teamSlug}/${fileName}`
- handleAvatar(image)
- this.setState({ cropping: false, uploaded: true, image: image })
- return avatar
+ await Azure.uploadBrowserDataToBlockBlob(Azure.Aborter.None, this.state.cropped, blockBlobURL)
+
+ const image = `${process.env.AZURE_STORAGE_URL}${teamSlug}/${fileName}?${Math.random()}`
+ handleImage(image)
+ let avatarImage = this.state.edit === 'avatar' ? image : null
+ let bannerImage = this.state.edit === 'banner' ? image : null
+ this.setState({ cropping: false, uploaded: true, change: false, avatarImage: avatarImage, bannerImage: bannerImage })
+ return image
}
- handleClickOpen () {
- this.setState({ open: true })
+ handleChangeImage (e, editImageType) {
+ e.preventDefault()
+ let crop = editImageType === 'avatar' ? { x: 10, y: 10, width: 200, height: 200 } : { x: 10, y: 10, width: 800, height: 200 }
+ this.setState({
+ edit: editImageType,
+ change: true,
+ crop: crop
+ })
+ }
+
+ cancelChangeImage () {
+ this.setState({ change: false })
+ }
+
+ handleClickOpen (e, editImageType) {
+ e.preventDefault()
+ this.setState({
+ open: true
+ })
}
handleClose () {
- this.setState({ open: false, src: null })
+ this.setState({ open: false, src: null, change: false })
}
}
@@ -248,7 +338,8 @@ UploadImage.propTypes = {
classes: PropTypes.object.isRequired,
team: PropTypes.object,
authId: PropTypes.string.isRequired,
- handleAvatar: PropTypes.func.isRequired
+ handleAvatar: PropTypes.func.isRequired,
+ handleBanner: PropTypes.func.isRequired
}
export default withStyles(styles)(UploadImage)
diff --git a/client/src/views/dashboard/components/ManageTeamDetails.js b/client/src/views/dashboard/components/ManageTeamDetails.js
index b4a736166..33eac05ed 100644
--- a/client/src/views/dashboard/components/ManageTeamDetails.js
+++ b/client/src/views/dashboard/components/ManageTeamDetails.js
@@ -5,10 +5,11 @@ import { withStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
import DetailsIcon from '@material-ui/icons/Details'
import Dialog from '@material-ui/core/Dialog'
-import DialogActions from '@material-ui/core/DialogActions'
-import DialogContent from '@material-ui/core/DialogContent'
-import DialogTitle from '@material-ui/core/DialogTitle'
import Typography from '@material-ui/core/Typography'
+import Card from '@material-ui/core/Card'
+import CardContent from '@material-ui/core/CardContent'
+import CardActions from '@material-ui/core/CardActions'
+import CardMedia from '@material-ui/core/CardMedia'
const styles = theme => ({
dialogContainer: {
@@ -18,6 +19,33 @@ const styles = theme => ({
},
buttonRight: {
justifyContent: 'flex-end'
+ },
+ cardGrid: {
+ padding: `${theme.spacing.unit * 8}px 0`
+ },
+ card: {
+ display: 'flex',
+ width: '100%'
+ },
+ cardDetails: {
+ display: 'flex',
+ flex: 1
+ },
+ cardContent: {
+ flex: 1
+ },
+ cardAvatarMedia: {
+ flex: 1,
+ width: 100,
+ height: 100,
+ maxWidth: 100,
+ justifyContent: 'flex-start'
+ },
+ cardBannerMedia: {
+ flex: 1,
+ width: 600,
+ height: 150,
+ justifyContent: 'flex-start'
}
})
@@ -35,7 +63,20 @@ export class ManageTeamDetails extends Component {
render () {
console.log(this.props.team)
+ const { classes } = this.props
const { name, members, profile, createdAt } = this.props.team
+ let avatar
+ let banner
+ if (profile.avatar !== undefined && profile.avatar !== 'a') {
+ avatar = profile.avatar
+ } else {
+ avatar = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EAvatar%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
+ }
+ if (profile.banner !== undefined && profile.banner !== 'a') {
+ banner = profile.banner
+ } else {
+ banner = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22800%22%20height%3D%22200%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23banner_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%3E%3Ctitle%3EBanner%20Placeholder%3C%2Ftitle%3E%3Crect%20stroke%3D%22null%22%20id%3D%22svg_1%22%20fill%3D%22%2355595c%22%20height%3D%22200%22%20width%3D%22800%22%2F%3E%3Cg%20stroke%3D%22null%22%20id%3D%22banner_164edaf95ee%22%3E%3Ctext%20stroke%3D%22null%22%20id%3D%22svg_3%22%20y%3D%22106.5%22%20x%3D%22367.73438%22%3EBanner%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
+ }
return (