diff --git a/api/src/graphql/TeamsConnectionsFragment.js b/api/src/graphql/TeamsConnectionsFragment.js new file mode 100644 index 000000000..89a22a8c4 --- /dev/null +++ b/api/src/graphql/TeamsConnectionsFragment.js @@ -0,0 +1,33 @@ +const gql = require('graphql-tag') + +const TEAMS_CONNECTIONS_FRAGMENT = gql`{ + edges { + node { + id + name + slug + owner + status { + status + reason + createdAt + } + createdAt + profile { + avatar + description + motto + updatedAt + } + members { + role + member { + alias + authId + } + } + } + } +}` + +module.exports = TEAMS_CONNECTIONS_FRAGMENT diff --git a/api/src/index.js b/api/src/index.js index 0386ba61b..6b4a5167d 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -14,6 +14,7 @@ const { validateIdToken } = require('./auth/validateIdToken') const { directiveResolvers } = require('./auth/authDirectives') const TEAMS_FRAGMENT = require('./graphql/TeamsFragment') +const TEAMS_CONNECTIONS_FRAGMENT = require('./graphql/TeamsConnectionsFragment') const createMember = async function (ctx, info, idToken) { console.log('createMember', idToken) @@ -47,36 +48,7 @@ const resolvers = { return ctx.db.query.member({ where: { authId } }, info) }, teams(parent, args, ctx, info) { - return ctx.db.query.teamsConnection({}, - `{ - edges { - node { - id - name - slug - owner - status { - status - reason - createdAt - } - createdAt - profile { - avatar - description - motto - updatedAt - } - members { - role - member { - alias - authId - } - } - } - } - }`) + return ctx.db.query.teamsConnection({}, TEAMS_CONNECTIONS_FRAGMENT) }, async teamById(parent, { id }, ctx, info) { return ctx.db.query.team({ where: { id } }, info) @@ -128,6 +100,13 @@ const resolvers = { return err }) }, + async updateTeamProfile(parent, { slug, owner, description, motto, avatar }, ctx, info) { + return ctx.db.mutation.updateTeam({data:{profile: {update: {description: description, motto: motto, avatar: avatar}}}, where:{slug: slug}}), TEAMS_FRAGMENT) + .catch((err) => { + console.log('createTeam error: ', err) + return err + }) + }, async deleteTeam(parent, { id }, ctx, info) { return ctx.db.mutation.deleteTeam({ where: { id } }, info) .catch((res) => { diff --git a/api/src/schema.graphql b/api/src/schema.graphql index 9e315174c..8b5d48d77 100644 --- a/api/src/schema.graphql +++ b/api/src/schema.graphql @@ -18,7 +18,8 @@ type Query { type Mutation { authenticate(idToken: String!): Member - createTeam(name: String!, slug: String, owner: String): Team @isAuthenticated + createTeam(name: String!, slug: String!, owner: String!): Team @isAuthenticated + updateTeamProfile(slug: String!, owner: String!, description: String, motto: String, avatar: String): Team @isAuthenticated deleteTeam(id: ID!): Team @isAuthenticated @isOwner(type: "Team") } diff --git a/client/src/graphql/teams/UpdateTeamProfileMutation.js b/client/src/graphql/teams/UpdateTeamProfileMutation.js new file mode 100644 index 000000000..6672a7a24 --- /dev/null +++ b/client/src/graphql/teams/UpdateTeamProfileMutation.js @@ -0,0 +1,34 @@ +/* eslint-disable no-unused-vars */ +import gql from 'graphql-tag' + +const CREATE_TEAM = gql` + mutation UpdateTeamMutation($slug: String!, $owner: String!, $description: String, $motto: String) { + createTeam(slug: $slug, owner: $owner, description: $description, motto: $motto) { + id + name + slug + owner + status { + status + reason + createdAt + } + createdAt + profile { + avatar + description + motto + updatedAt + } + members { + role + member { + alias + authId + } + } + } + } +` + +export default CREATE_TEAM diff --git a/client/src/views/dashboard/ManageTeams.js b/client/src/views/dashboard/ManageTeams.js index ecf65c9db..175c4aded 100644 --- a/client/src/views/dashboard/ManageTeams.js +++ b/client/src/views/dashboard/ManageTeams.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types' import Typography from '@material-ui/core/Typography' import { withStyles } from '@material-ui/core/styles' -import TeamTable from './components/TeamTable' +import ManageTeamsList from './components/ManageTeamsList' const styles = theme => ({ tableContainer: { @@ -15,10 +15,10 @@ const styles = theme => ({ const ManageTeams = ({ classes }) => (
- Teams + Manage Your Teams
- +
) diff --git a/client/src/views/dashboard/components/ManageTeamEdit.js b/client/src/views/dashboard/components/ManageTeamEdit.js new file mode 100644 index 000000000..d10dd5728 --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamEdit.js @@ -0,0 +1,133 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { withRouter } from 'react-router-dom' +import Button from '@material-ui/core/Button' +import AddIcon from '@material-ui/icons/Add' +import TextField from '@material-ui/core/TextField' +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' + +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.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.team) + return ( +
+ + + Edit Team Details + + Team Creation + Team Motto: + + + + + + + +
+ ) + } + + 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) { + 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 }) + } +} + +ManageTeamEdit.propTypes = { + classes: PropTypes.object.isRequired, + team: PropTypes.object.isRequired, + createTeamMutation: PropTypes.function +} + +export default withRouter(ManageTeamEdit) diff --git a/client/src/views/dashboard/components/ManageTeamsDetails.js b/client/src/views/dashboard/components/ManageTeamsDetails.js new file mode 100644 index 000000000..65a988215 --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamsDetails.js @@ -0,0 +1,89 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import CssBaseline from '@material-ui/core/CssBaseline' +import Typography from '@material-ui/core/Typography' +import Paper from '@material-ui/core/Paper' +import { withStyles } from '@material-ui/core/styles' + +import { Link } from 'react-router-dom' + +const styles = theme => ({ + root: { + flexGrow: 1 + }, + '@global': { + body: { + backgroundColor: theme.palette.common.white + } + }, + layout: { + width: 'auto', + marginLeft: theme.spacing.unit * 3, + marginRight: theme.spacing.unit * 3, + marginBottom: theme.spacing.unit * 6, + [theme.breakpoints.up(900 + theme.spacing.unit * 3 * 2)]: { + width: 900, + marginLeft: 'auto', + marginRight: 'auto' + } + }, + paper: { + marginTop: theme.spacing.unit * 3, + marginBottom: theme.spacing.unit * 3, + padding: theme.spacing.unit * 2, + [theme.breakpoints.up(600 + theme.spacing.unit * 3 * 2)]: { + marginTop: theme.spacing.unit * 6, + marginBottom: theme.spacing.unit * 6, + padding: theme.spacing.unit * 3 + } + }, + heroContent: { + maxWidth: 600, + margin: '0 auto', + padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px` + } +}) + +const ManageTeamsDetails = ({ classes, team }) => ( + + +
+ +
+ ← Back to all teams + + {team.name} + + + {team.createdAt} + + + Members: {team.members.length} + + + Team Admin: + { + team.members.map(member => { + if (member.role === 'OWNER' || member.role === 'ADMIN') { + return member.member.alias + } + }) + } + +
+
+
+
+) +ManageTeamsDetails.propTypes = { + classes: PropTypes.object.isRequired, + team: PropTypes.object.isRequired +} + +export default withStyles(styles)(ManageTeamsDetails) diff --git a/client/src/views/dashboard/components/ManageTeamsItem.js b/client/src/views/dashboard/components/ManageTeamsItem.js new file mode 100644 index 000000000..7c00639d9 --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamsItem.js @@ -0,0 +1,55 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import Grid from '@material-ui/core/Grid' +import Card from '@material-ui/core/Card' +import CardActionArea from '@material-ui/core/CardActionArea' +import CardActions from '@material-ui/core/CardActions' +import CardContent from '@material-ui/core/CardContent' +import CardMedia from '@material-ui/core/CardMedia' +import Button from '@material-ui/core/Button' +import Typography from '@material-ui/core/Typography' + +import { Link } from 'react-router-dom' + +export const ManageTeamsItem = ({ classes, team }) => ( + + + + + + + {team.name} + + + {team.createdAt} + + + Members: 1 + + + Now recruiting! + + + + + + + + + + +) + +ManageTeamsItem.propTypes = { + classes: PropTypes.object.isRequired, + team: PropTypes.object.isRequired +} + +export default ManageTeamsItem diff --git a/client/src/views/dashboard/components/ManageTeamsList.js b/client/src/views/dashboard/components/ManageTeamsList.js new file mode 100644 index 000000000..b02592c8e --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamsList.js @@ -0,0 +1,128 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Query } from 'react-apollo' + +import Typography from '@material-ui/core/Typography' +import Grid from '@material-ui/core/Grid' +import { withStyles } from '@material-ui/core/styles' + +import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' + +import { isEmpty } from '../../../utils/js-helpers' + +import ManageTeamsItem from './ManageTeamsItem' +import ManageTeamsDetails from './ManageTeamsDetails' + +const styles = theme => ({ + heroContent: { + maxWidth: 600, + margin: '0 auto', + padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px` + }, + cardGrid: { + padding: `${theme.spacing.unit * 8}px 0` + }, + card: { + height: '100%', + display: 'flex', + flexDirection: 'column' + }, + cardMedia: { + paddingTop: '56.25%' // 16:9 + }, + cardContent: { + flexGrow: 1 + }, + buttonRight: { + justifyContent: 'flex-end' + } +}) + +export const ManageTeamsList = ({ classes, match }) => ( + + {({ loading, error, data }) => { + console.log('GET_TEAMS_BY_OWNER: ', loading, error, data, match) + let slug = null + if (!isEmpty(match.params) && match.params.slug) slug = match.params.slug + + let errors + let queryLoader + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => { + return ( + + {message} + + ) + }) + } + if (!loading && !error) { + if (data.teams.edges.length > 0) { + if (slug !== null) { + return ( + + {!loading && + data.teams.edges.map(team => { + if (team.node.slug === slug) { + return ( + + ) + } + })} + {queryLoader} + {errors} + + ) + } else { + return ( + +
+ + Teams + +
+ + {!loading && + data.teams.edges.map(team => ( + + ))} + {queryLoader} + {errors} + +
+ ) + } + } + } else { + return ( + + + Loading... + + {queryLoader} + {errors} + + ) + } + }} +
+) + +ManageTeamsList.propTypes = { + classes: PropTypes.object.isRequired, + match: PropTypes.object +} + +export default withStyles(styles)(ManageTeamsList) diff --git a/client/src/views/teams/components/TeamsList.js b/client/src/views/teams/components/TeamsList.js index 8ae962ead..64493cdff 100644 --- a/client/src/views/teams/components/TeamsList.js +++ b/client/src/views/teams/components/TeamsList.js @@ -41,7 +41,7 @@ const styles = theme => ({ export const TeamsList = ({ classes, match }) => ( {({ loading, error, data }) => { - console.log('GET_TEAMS_BY_OWNER: ', loading, error, data, match) + console.log('GET_ALL_TEAMS: ', loading, error, data, match) let slug = null if (!isEmpty(match.params) && match.params.slug) slug = match.params.slug