Client: Manage Team Dialogs
This commit is contained in:
1 parent
5b521b3620
commit
4e75489949
11 files changed
+593
-144
No files matched your search
@@ -71,8 +71,8 @@ const isLoggedIn = async ctx => {
|
||||
|
||||
|
||||
const isRequestingMemberAlsoOwner = ({ ctx, memberId, type, typeId }) =>
|
||||
ctx.db.exists[type]({ id: typeId, owner: { auth0id: memberId } })
|
||||
const isRequestingMember = ({ ctx, memberId }) => ctx.db.exists.Member({ auth0id: memberId })
|
||||
ctx.db.exists[type]({ slug: typeId, owner: memberId })
|
||||
const isRequestingMember = ({ ctx, memberId }) => ctx.db.exists.Member({ authId: memberId })
|
||||
|
||||
const directiveResolvers = {
|
||||
isAuthenticated: async (next, source, args, ctx) => {
|
||||
@@ -89,12 +89,14 @@ const directiveResolvers = {
|
||||
throw new Error(`Unauthorized, incorrect role`)
|
||||
},
|
||||
isOwner: async (next, source, { type }, ctx) => {
|
||||
const { id: typeId } =
|
||||
console.log('directive isOwner: ', source, type, ctx)
|
||||
const { slug: typeId } =
|
||||
source && source.id
|
||||
? source
|
||||
: ctx.request.body.variables ? ctx.request.body.variables : { id: null }
|
||||
const { auth0id: memberId } = await isLoggedIn(ctx)
|
||||
console.log('directive isOwner 0: ', type, typeId, memberId)
|
||||
const user = await isLoggedIn(ctx)
|
||||
console.log('directive isOwner 0: ', typeId, user.sub)
|
||||
const memberId = user.sub
|
||||
const isOwner =
|
||||
type === `Member`
|
||||
? memberId === typeId
|
||||
@@ -106,14 +108,14 @@ const directiveResolvers = {
|
||||
throw new Error(`Unauthorized, must be owner`)
|
||||
},
|
||||
isOwnerOrHasRole: async (next, source, { roles, type }, ctx, ...p) => {
|
||||
const { auth0id: memberId } = await isLoggedIn(ctx)
|
||||
const { authId: memberId } = await isLoggedIn(ctx)
|
||||
console.log('directive isOwnerOrHasRole 1: ', memberId, roles, type)
|
||||
if(memberId === undefined && role=== undefined) throw new Error(`Not logged in`)
|
||||
if (roles.includes(role)) {
|
||||
return next()
|
||||
}
|
||||
|
||||
const { auth0id: typeId } = ctx.request.body.variables
|
||||
const { authId: typeId } = ctx.request.body.variables
|
||||
const isOwner = await isRequestingMemberAlsoOwner({
|
||||
ctx,
|
||||
memberId,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const DELETE_TEAM = gql`
|
||||
mutation deleteTeam($id: ID!) {
|
||||
deleteTeam(id: $id) {
|
||||
mutation deleteTeam($slug: String!) {
|
||||
deleteTeam(slug: $slug) {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import Card from '@material-ui/core/Card'
|
||||
import CardContent from '@material-ui/core/CardContent'
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
margin: '1.5em',
|
||||
padding: '3em'
|
||||
},
|
||||
cardDetails: {
|
||||
display: 'flex',
|
||||
flex: 1
|
||||
},
|
||||
cardContent: {
|
||||
flex: 1
|
||||
}
|
||||
})
|
||||
|
||||
export const MessageCard = ({ classes, message, children }) => (
|
||||
<Card className={classes.card}>
|
||||
<div className={classes.cardDetails}>
|
||||
<CardContent className={classes.cardContent}>
|
||||
<Typography variant='headline' align='center' gutterBottom>{message}</Typography>
|
||||
{children}
|
||||
</CardContent>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
|
||||
MessageCard.propTypes = {
|
||||
children: PropTypes.node,
|
||||
classes: PropTypes.object.isRequired,
|
||||
message: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default withStyles(styles)(MessageCard)
|
||||
@@ -0,0 +1,3 @@
|
||||
import MessageCard from './MessageCard'
|
||||
|
||||
export { MessageCard }
|
||||
@@ -34,6 +34,13 @@ const styles = theme => ({
|
||||
aawebMedia: {
|
||||
width: '100%',
|
||||
height: 320
|
||||
},
|
||||
dashLink: {
|
||||
float: 'right',
|
||||
color: '#111',
|
||||
fontSize: 16,
|
||||
textDecoration: 'none',
|
||||
paddingRight: '1em'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Mutation } from 'react-apollo'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import AddIcon from '@material-ui/icons/Add'
|
||||
import TextField from '@material-ui/core/TextField'
|
||||
import FormControl from '@material-ui/core/FormControl'
|
||||
import FormHelperText from '@material-ui/core/FormHelperText'
|
||||
import Dialog from '@material-ui/core/Dialog'
|
||||
import DialogActions from '@material-ui/core/DialogActions'
|
||||
import DialogContent from '@material-ui/core/DialogContent'
|
||||
import DialogContentText from '@material-ui/core/DialogContentText'
|
||||
import DialogTitle from '@material-ui/core/DialogTitle'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
|
||||
import { getItem } from '../../../utils/local-storage'
|
||||
import { isEmpty } from '../../../utils/js-helpers'
|
||||
|
||||
import CREATE_TEAM from '../../../graphql/teams/CreateTeamMutation'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
// import { checkGraphQLError } from '../../../utils/graphql-errors'
|
||||
|
||||
const styles = theme => ({
|
||||
dialogStyle: {
|
||||
padding: '3em'
|
||||
},
|
||||
buttonRight: {
|
||||
// position: 'absolute',
|
||||
// right: '3em'
|
||||
marginTop: '1em',
|
||||
marginRight: 'auto',
|
||||
marginLeft: 'auto',
|
||||
display: 'block',
|
||||
lineHeight: '1em'
|
||||
}
|
||||
})
|
||||
|
||||
export class CreateTeamDialog extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
this.validate = this.validate.bind(this)
|
||||
this.slugify = this.slugify.bind(this)
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
name: '',
|
||||
errors: {
|
||||
name: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { classes, authId } = this.props
|
||||
return (
|
||||
<Mutation
|
||||
mutation={CREATE_TEAM}
|
||||
refetchQueries={[
|
||||
{
|
||||
query: GET_TEAMS_BY_OWNER,
|
||||
variables: { authId }
|
||||
}
|
||||
]}
|
||||
>
|
||||
{(createTeam, { loading, error, data }) => {
|
||||
let errors
|
||||
let loader = null
|
||||
if (loading) {
|
||||
loader = <Typography variant='subheading'>Submitting team...</Typography>
|
||||
}
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
// const displayMessage = checkGraphQLError(message)
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Button variant='fab' color='primary' aria-label='Add' className={classes.buttonRight} onClick={this.handleClickOpen}>
|
||||
<AddIcon />
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<DialogTitle id='form-dialog-title'>Create a Team</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>Team Name:</DialogContentText>
|
||||
<FormControl required error={e => (this.state.errors.name !== '' || error)}>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin='dense'
|
||||
id='teamname'
|
||||
label='Team Name'
|
||||
type='text'
|
||||
fullWidth
|
||||
value={this.state.name}
|
||||
onChange={this.handleChange}
|
||||
error={e => this.state.errors.name !== '' || error}
|
||||
/>
|
||||
{this.state.errors.name !== '' && (<FormHelperText>{this.state.errors.name}</FormHelperText>)}
|
||||
{error && (<FormHelperText>{errors}</FormHelperText>)}
|
||||
{loader}
|
||||
</FormControl>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={e => {
|
||||
this.handleSubmit(e, createTeam, this.state.name)
|
||||
}} color='primary'>
|
||||
Create Team
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Mutation>
|
||||
)
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
const errors = this.validate(e.target.value)
|
||||
if (isEmpty(errors)) {
|
||||
this.setState({ errors: { name: '' } })
|
||||
this.setState({ name: e.target.value })
|
||||
} else {
|
||||
this.setState({ errors: errors })
|
||||
this.setState({ name: e.target.value })
|
||||
}
|
||||
}
|
||||
|
||||
async handleSubmit (e, createTeam, name) {
|
||||
e.preventDefault()
|
||||
const currentUser = await getItem('user')
|
||||
let authId = JSON.parse(currentUser)
|
||||
authId = authId.authId
|
||||
console.log('createTeam submit: ', authId, name)
|
||||
const slug = this.slugify(name)
|
||||
await createTeam({ variables: { name, slug, owner: authId } })
|
||||
this.setState({ name: '' })
|
||||
}
|
||||
|
||||
validate (data) {
|
||||
const errors = {}
|
||||
if (data === '') errors.name = 'Please enter a team name'
|
||||
return errors
|
||||
}
|
||||
|
||||
slugify (string) {
|
||||
const a = 'àáäâãåèéëêìíïîòóöôùúüûñçßÿœæŕśńṕẃǵǹḿǘẍźḧ·/_,:;'
|
||||
const b = 'aaaaaaeeeeiiiioooouuuuncsyoarsnpwgnmuxzh------'
|
||||
const p = new RegExp(a.split('').join('|'), 'g')
|
||||
|
||||
return string
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, '-') // Replace spaces with -
|
||||
.replace(p, c => b.charAt(a.indexOf(c))) // Replace special characters
|
||||
.replace(/&/g, '-and-') // Replace & with 'and'
|
||||
.replace(/[^\w-]+/g, '') // Remove all non-word characters
|
||||
.replace(/--+/g, '-') // Replace multiple - with single -
|
||||
.replace(/^-+/, '') // Trim - from start of text
|
||||
.replace(/-+$/, '') // Trim - from end of text
|
||||
}
|
||||
}
|
||||
|
||||
CreateTeamDialog.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
authId: PropTypes.string
|
||||
}
|
||||
|
||||
export default withStyles(styles)(CreateTeamDialog)
|
||||
@@ -2,6 +2,7 @@ import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Query } from 'react-apollo'
|
||||
import { withStateHandlers, lifecycle, compose } from 'recompose'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
@@ -9,7 +10,8 @@ import Grid from '@material-ui/core/Grid'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import DashTeamItem from './DashTeamItem'
|
||||
import CreateTeamWrapper from './CreateTeamWrapper'
|
||||
import CreateTeamDialog from './CreateTeamDialog'
|
||||
import { MessageCard } from '../../common/'
|
||||
|
||||
import { isDefined, isString } from '../../../utils/js-helpers'
|
||||
import { getItem } from '../../../utils/local-storage'
|
||||
@@ -38,11 +40,10 @@ export const DashTeam = ({ classes, user = null }) => {
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Grid item md={6}>
|
||||
<Grid item md={6} style={{ position: 'relative' }}>
|
||||
<Typography variant='display1' gutterBottom>
|
||||
Teams
|
||||
Teams <Link to='/manage-teams' className={classes.dashLink}>Manage Teams</Link>
|
||||
</Typography>
|
||||
<CreateTeamWrapper authId={authId} />
|
||||
<Query query={GET_TEAMS_BY_OWNER} variables={{ authId }}>
|
||||
{({ loading, error, data }) => {
|
||||
console.log('GET_TEAMS_BY_OWNER: ', loading, error, data)
|
||||
@@ -70,6 +71,16 @@ export const DashTeam = ({ classes, user = null }) => {
|
||||
{loader}
|
||||
</Grid>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid xs={10}>
|
||||
<MessageCard message='No teams yet...'>
|
||||
<CreateTeamDialog authId={authId} />
|
||||
</MessageCard>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { Mutation } from 'react-apollo'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import DeleteIcon from '@material-ui/icons/Delete'
|
||||
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 DELETE_TEAM from '../../../graphql/teams/DeleteTeamMutation'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import { checkGraphQLError } from '../../../utils/graphql-errors'
|
||||
|
||||
export class ManageTeamDelete extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
motto: '',
|
||||
description: ''
|
||||
}
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
this.setState({ name: e.target.value })
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log(this.props, this.props.slug)
|
||||
const authId = this.props.authId
|
||||
return (
|
||||
<Mutation
|
||||
mutation={DELETE_TEAM}
|
||||
refetchQueries={[
|
||||
{
|
||||
query: GET_TEAMS_BY_OWNER,
|
||||
variables: { authId }
|
||||
}
|
||||
]}
|
||||
update={(cache, { data: { deleteTeam } }) => {
|
||||
const data = cache.readQuery({ query: GET_TEAMS_BY_OWNER })
|
||||
console.log('Mutation cache update: ', deleteTeam, data)
|
||||
data.getTeamsByOwner.push(deleteTeam)
|
||||
cache.writeQuery({ query: GET_TEAMS_BY_OWNER, data })
|
||||
}}
|
||||
>
|
||||
{(deleteTeam, { loading, error, data }) => {
|
||||
let errors
|
||||
let loader
|
||||
if (loading) {
|
||||
loader = <Typography variant='caption'>Submitting team...</Typography>
|
||||
}
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
const displayMessage = checkGraphQLError(message)
|
||||
console.log('createTeam error:', displayMessage)
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Button size='small' color='primary' className={this.props.classes.buttonRight} onClick={this.handleClickOpen}>
|
||||
<DeleteIcon /> Delete
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<DialogTitle id='form-dialog-title'>Delete Team Team</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant='subheading' color='primary'>DANGER - Deleting your team cannot be undone</Typography>
|
||||
<Typography variant='subheading'>Are you sure you want to delete this team?</Typography>
|
||||
{loader}
|
||||
{errors}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={e => {
|
||||
this.handleSubmit(e, deleteTeam, this.props.slug, authId)
|
||||
}} color='primary'>
|
||||
Delete Team
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Mutation>
|
||||
)
|
||||
}
|
||||
|
||||
async handleSubmit (e, deleteTeam, slug, authId) {
|
||||
e.preventDefault()
|
||||
await deleteTeam({ variables: { slug, owner: authId } })
|
||||
}
|
||||
}
|
||||
|
||||
ManageTeamDelete.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
slug: PropTypes.string.isRequired,
|
||||
authId: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default withRouter(ManageTeamDelete)
|
||||
@@ -1,8 +1,10 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { Mutation } from 'react-apollo'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import AddIcon from '@material-ui/icons/Add'
|
||||
import EditIcon from '@material-ui/icons/Edit'
|
||||
import TextField from '@material-ui/core/TextField'
|
||||
import Dialog from '@material-ui/core/Dialog'
|
||||
import DialogActions from '@material-ui/core/DialogActions'
|
||||
@@ -13,15 +15,19 @@ import Typography from '@material-ui/core/Typography'
|
||||
|
||||
import { getItem } from '../../../utils/local-storage'
|
||||
|
||||
import UPDATE_TEAM_PROFILE from '../../../graphql/teams/UpdateTeamProfileMutation'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import { checkGraphQLError } from '../../../utils/graphql-errors'
|
||||
|
||||
export class ManageTeamEdit extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
this.handlePost = this.handlePost.bind(this)
|
||||
this.slugify = this.slugify.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
@@ -30,6 +36,101 @@ export class ManageTeamEdit extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log(this.props, this.props.slug)
|
||||
return (
|
||||
<Mutation
|
||||
mutation={UPDATE_TEAM_PROFILE}
|
||||
update={(cache, { data: { deleteTeam } }) => {
|
||||
const data = cache.readQuery({ query: GET_TEAMS_BY_OWNER })
|
||||
console.log('Mutation cache update: ', deleteTeam, data)
|
||||
data.getTeamsByOwner.push(deleteTeam)
|
||||
cache.writeQuery({ query: GET_TEAMS_BY_OWNER, data })
|
||||
}}
|
||||
>
|
||||
{(updateTeamProfile, { loading, error, data }) => {
|
||||
let errors
|
||||
let loader
|
||||
let description
|
||||
let motto
|
||||
if (loading) {
|
||||
loader = <Typography variant='caption'>Submitting team...</Typography>
|
||||
}
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
const displayMessage = checkGraphQLError(message)
|
||||
console.log('updateTeamProfile error:', displayMessage)
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Button size='small' color='primary' className={this.props.classes.buttonRight} onClick={this.handleClickOpen}>
|
||||
<EditIcon /> Edit
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<DialogTitle id='form-dialog-title'>Edit Team Details</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant='subheading'>Team Creation</Typography>
|
||||
<DialogContentText>Team Motto:</DialogContentText>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin='dense'
|
||||
id='teammotto'
|
||||
label='Team Motto'
|
||||
type='text'
|
||||
fullWidth
|
||||
value={this.state.motto}
|
||||
onChange={this.handleChange}
|
||||
inputRef={node => {
|
||||
motto = node
|
||||
}}
|
||||
/>
|
||||
<DialogContentText>Team description:</DialogContentText>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin='dense'
|
||||
id='teamDescription'
|
||||
label='Team Description'
|
||||
type='text'
|
||||
rows={4}
|
||||
multiline
|
||||
fullWidth
|
||||
value={this.state.description}
|
||||
onChange={this.handleChange}
|
||||
inputRef={node => {
|
||||
description = node
|
||||
}}
|
||||
/>
|
||||
{loader}
|
||||
{errors}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={e => {
|
||||
this.handleSubmit(e, updateTeamProfile, this.props.slug, description, motto)
|
||||
}} color='primary'>
|
||||
Update Team
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Mutation>
|
||||
)
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
@@ -39,95 +140,29 @@ export class ManageTeamEdit extends Component {
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
this.setState({ name: e.target.value })
|
||||
switch (e.target.id) {
|
||||
case 'motto':
|
||||
this.setState({ motto: e.target.value })
|
||||
break
|
||||
case 'description':
|
||||
this.setState({ description: e.target.value })
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log(this.props, this.props.team)
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
variant='extendedFab'
|
||||
aria-label='AddTeam'
|
||||
className={this.props.classes.button}
|
||||
onClick={this.handleClickOpen}
|
||||
>
|
||||
<AddIcon className={this.props.classes.extendedIcon} />
|
||||
<Typography variant='subheading'>Create A Team</Typography>
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<DialogTitle id='form-dialog-title'>Edit Team Details</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant='subheading'>Team Creation</Typography>
|
||||
<DialogContentText>Team Motto:</DialogContentText>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin='dense'
|
||||
id='teammotto'
|
||||
label='Team Motto'
|
||||
type='text'
|
||||
fullWidth
|
||||
value={this.state.mottoe}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={this.handlePost} color='primary'>
|
||||
Create Team
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
slugify (string) {
|
||||
const a = 'àáäâãåèéëêìíïîòóöôùúüûñçßÿœæŕśńṕẃǵǹḿǘẍźḧ·/_,:;'
|
||||
const b = 'aaaaaaeeeeiiiioooouuuuncsyoarsnpwgnmuxzh------'
|
||||
const p = new RegExp(a.split('').join('|'), 'g')
|
||||
|
||||
return string
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, '-') // Replace spaces with -
|
||||
.replace(p, c => b.charAt(a.indexOf(c))) // Replace special characters
|
||||
.replace(/&/g, '-and-') // Replace & with 'and'
|
||||
.replace(/[^\w-]+/g, '') // Remove all non-word characters
|
||||
.replace(/--+/g, '-') // Replace multiple - with single -
|
||||
.replace(/^-+/, '') // Trim - from start of text
|
||||
.replace(/-+$/, '') // Trim - from end of text
|
||||
}
|
||||
|
||||
async handlePost (e) {
|
||||
async handleSubmit (e, updateTeamProfile, slug, description, motto) {
|
||||
e.preventDefault()
|
||||
const { name } = this.state
|
||||
const slug = this.slugify(name)
|
||||
const currentUser = await getItem('user')
|
||||
let authId = JSON.parse(currentUser)
|
||||
authId = authId.sub
|
||||
console.log('createPage cu:', JSON.parse(currentUser))
|
||||
await this.props.createTeamMutation({
|
||||
variables: {
|
||||
name,
|
||||
slug,
|
||||
owner: authId
|
||||
}
|
||||
})
|
||||
this.setState({ open: false })
|
||||
authId = authId.authId
|
||||
await updateTeamProfile({ variables: { slug, owner: authId, description: description, motto: motto } })
|
||||
}
|
||||
}
|
||||
|
||||
ManageTeamEdit.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
team: PropTypes.object.isRequired,
|
||||
createTeamMutation: PropTypes.function
|
||||
slug: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default withRouter(ManageTeamEdit)
|
||||
@@ -10,8 +10,9 @@ import Button from '@material-ui/core/Button'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
|
||||
import ManageTeamDelete from './ManageTeamDelete'
|
||||
import ManageTeamEdit from './ManageTeamEdit'
|
||||
|
||||
export const ManageTeamsItem = ({ classes, team }) => (
|
||||
export const ManageTeamsItem = ({ classes, team, authId }) => (
|
||||
<Grid item xs={12}>
|
||||
<Card className={classes.card}>
|
||||
<div className={classes.cardDetails}>
|
||||
@@ -32,10 +33,8 @@ export const ManageTeamsItem = ({ classes, team }) => (
|
||||
<Button size='small' color='primary' className={classes.buttonRight}>
|
||||
Details
|
||||
</Button>
|
||||
<ManageTeamDelete classes={classes} slug={team.slug} />
|
||||
<Button size='small' color='primary' className={classes.buttonRight}>
|
||||
Delete
|
||||
</Button>
|
||||
<ManageTeamEdit classes={classes} slug={team.slug} authId={authId} />
|
||||
<ManageTeamDelete classes={classes} slug={team.slug} authId={authId} />
|
||||
</CardActions>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -44,7 +43,8 @@ export const ManageTeamsItem = ({ classes, team }) => (
|
||||
|
||||
ManageTeamsItem.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
team: PropTypes.object.isRequired
|
||||
team: PropTypes.object.isRequired,
|
||||
authId: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default ManageTeamsItem
|
||||
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types'
|
||||
import { Query } from 'react-apollo'
|
||||
import { withStateHandlers, lifecycle, compose } from 'recompose'
|
||||
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
@@ -13,6 +12,8 @@ import { getItem } from '../../../utils/local-storage'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import ManageTeamsItem from './ManageTeamsItem'
|
||||
import CreateTeamDialog from './CreateTeamDialog'
|
||||
import { MessageCard } from '../../common/'
|
||||
|
||||
const styles = theme => ({
|
||||
heroContent: {
|
||||
@@ -55,53 +56,74 @@ export const ManageTeamsList = ({ classes, user = null }) => {
|
||||
if (isDefined(owner.authId)) authId = owner.authId
|
||||
}
|
||||
console.log('ManageTeamsList 2: ', owner, authId)
|
||||
if (authId === undefined || authId === null) {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid>
|
||||
<MessageCard message='Loading...' />
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Query query={GET_TEAMS_BY_OWNER} fetchPolicy='network-only' variables={{ authId }}>
|
||||
{({ loading, error, data }) => {
|
||||
console.log('GET_TEAMS_BY_OWNER: ', loading, error, data)
|
||||
|
||||
return (
|
||||
<Query query={GET_TEAMS_BY_OWNER} fetchPolicy='network-only' variables={{ authId }}>
|
||||
{({ loading, error, data }) => {
|
||||
console.log('GET_TEAMS_BY_OWNER: ', loading, error, data)
|
||||
|
||||
let errors
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
if (!loading && !error) {
|
||||
if (data.teamsByOwner.length > 0) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
let errors = null
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
return (
|
||||
<MessageCard message={message} />
|
||||
)
|
||||
})
|
||||
}
|
||||
if (!loading && !error) {
|
||||
if (data.teamsByOwner.length > 0) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid container spacing={40}>
|
||||
{!loading &&
|
||||
data.teamsByOwner.map(team => (
|
||||
<ManageTeamsItem
|
||||
key={team.id}
|
||||
team={team}
|
||||
classes={classes}
|
||||
authId={authId}
|
||||
/>
|
||||
))}
|
||||
<MessageCard message='Create another team'>
|
||||
<CreateTeamDialog authId={authId} />
|
||||
</MessageCard>
|
||||
{errors}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
{!loading &&
|
||||
data.teamsByOwner.map(team => (
|
||||
<ManageTeamsItem
|
||||
key={team.id}
|
||||
team={team}
|
||||
classes={classes}
|
||||
/>
|
||||
))}
|
||||
{errors}
|
||||
<Grid xs={10}>
|
||||
<MessageCard message='You don’t have any teams. Create one!'>
|
||||
<CreateTeamDialog authId={authId} />
|
||||
</MessageCard>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid xs={12}>
|
||||
<MessageCard message='Loading...' />
|
||||
if (errors !== null) (<MessageCard message={errors} />)
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Typography variant='subheading' gutterBottom>
|
||||
Loading...
|
||||
</Typography>
|
||||
{errors}
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
}}
|
||||
</Query>
|
||||
)
|
||||
}}
|
||||
</Query>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ManageTeamsList.propTypes = {
|
||||
|
||||
Reference in new issue
Block a user