Client: Teams page basic

This commit is contained in:
Barry Low committed 2018-09-17 12:38:42 -07:00
1 parent 432a5c076f
commit 3735f85c2e
15 files changed
+286 -95

No files matched your search

+18 -13
View File
@@ -568,7 +568,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -614,7 +614,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -923,7 +923,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -1462,7 +1462,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -1640,7 +1640,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -4084,6 +4084,11 @@
"iterall": "^1.2.1"
}
},
"graphql-tag": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.9.2.tgz",
"integrity": "sha512-qnNmof9pAqj/LUzs3lStP0Gw1qhdVCUS7Ab7+SUB6KD5aX1uqxWQRwMnOGTkhKuLvLNIs1TvNz+iS9kUGl1MhA=="
},
"graphql-tools": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-3.1.1.tgz",
@@ -4997,7 +5002,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -5366,7 +5371,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
@@ -6693,7 +6698,7 @@
},
"graphql-import": {
"version": "0.4.5",
"resolved": "http://registry.npmjs.org/graphql-import/-/graphql-import-0.4.5.tgz",
"resolved": "https://registry.npmjs.org/graphql-import/-/graphql-import-0.4.5.tgz",
"integrity": "sha512-G/+I08Qp6/QGTb9qapknCm3yPHV0ZL7wbaalWFpxsfR8ZhZoTBe//LsbsCKlbALQpcMegchpJhpTSKiJjhaVqQ==",
"dev": true,
"requires": {
@@ -7590,7 +7595,7 @@
"dependencies": {
"commander": {
"version": "2.8.1",
"resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"dev": true,
"requires": {
@@ -8178,7 +8183,7 @@
},
"table": {
"version": "4.0.3",
"resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz",
"resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz",
"integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==",
"dev": true,
"requires": {
@@ -8239,7 +8244,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -8504,7 +8509,7 @@
},
"buffer": {
"version": "3.6.0",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz",
"integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=",
"dev": true,
"requires": {
@@ -9087,7 +9092,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
+1
View File
@@ -11,6 +11,7 @@
"dotenv": "^6.0.0",
"express-jwt": "^5.3.1",
"graphql-import": "^0.6.0",
"graphql-tag": "^2.9.2",
"graphql-tools": "3.1.1",
"graphql-yoga": "^1.16.1",
"jsonwebtoken": "^8.3.0",
+29
View File
@@ -0,0 +1,29 @@
const gql = require('graphql-tag')
const TEAMS_FRAGMENT = gql`{
id
name
slug
owner
status {
status
reason
createdAt
}
createdAt
profile {
avatar
description
motto
updatedAt
}
members {
role
member {
alias
authId
}
}
}`
module.exports = TEAMS_FRAGMENT
+4 -33
View File
@@ -13,6 +13,8 @@ const { getMember } = require('./auth/middleware/getMember')
const { validateIdToken } = require('./auth/validateIdToken')
const { directiveResolvers } = require('./auth/authDirectives')
const TEAMS_FRAGMENT = require('./graphql/TeamsFragment')
const createMember = async function (ctx, info, idToken) {
console.log('createMember', idToken)
const member = await ctx.db.mutation.upsertMember({
@@ -84,32 +86,7 @@ const resolvers = {
},
async teamsByOwner(parent, { ownerId }, ctx, info) {
console.log('teamsByOwner: ', ctx.user)
return ctx.db.query.teams({where: { owner: ownerId }},
`{
id
name
slug
owner
status {
status
reason
createdAt
}
createdAt
profile {
avatar
description
motto
updatedAt
}
members {
role
member {
alias
authId
}
}
}`)
return ctx.db.query.teams({where: { owner: ownerId }}, TEAMS_FRAGMENT)
},
async owner(parent, args, ctx, info) {
console.log('resolver.query.owner ctx: ', ctxMember(ctx))
@@ -145,13 +122,7 @@ const resolvers = {
return member
},
async createTeam(parent, { name, slug, owner }, ctx, info) {
return ctx.db.mutation.createTeam({
data: {
name: name,
slug: slug,
owner: owner
}
}, info)
return ctx.db.mutation.createTeam({ data: { name: name, slug: slug, owner: owner, members: { create: { member:{ connect:{ authId: owner} }, role: 'OWNER' } } } }, TEAMS_FRAGMENT)
.catch((err) => {
console.log('createTeam error: ', err)
return err
+2
View File
@@ -21,6 +21,7 @@ import {
Callback,
Home,
Dashboard,
Teams,
theme,
globalStyles
} from './views'
@@ -148,6 +149,7 @@ class App extends Component {
<NavBar auth={auth} />
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/teams' component={Teams} />
<Route
exact
path='/(dashboard|manage-teams|team-members|settings)/'
+6 -1
View File
@@ -167,7 +167,12 @@ class Auth {
let user = JSON.parse(getUser)
if (new Date().getTime() < getExpires * 1000) {
console.log('handleAuth.user exp: ', user, getExpires, window.location.href)
console.log(
'handleAuth.user exp: ',
user,
getExpires,
window.location.href
)
return user
}
+2 -2
View File
@@ -1,7 +1,7 @@
/* eslint-disable no-unused-vars */
import gql from 'graphql-tag'
export const GetAllTeamsQuery = gql`
export const GET_ALL_TEAMS_QUERY = gql`
query teamsQuery {
teams {
edges {
@@ -35,4 +35,4 @@ export const GetAllTeamsQuery = gql`
}
`
export default GetAllTeamsQuery
export default GET_ALL_TEAMS_QUERY
+22 -26
View File
@@ -2,32 +2,28 @@
import gql from 'graphql-tag'
export const TEAMS_FRAGMENT = gql`
fragment TeamsRespons on teamsConnection {
edges {
node {
id
name
slug
owner
status {
status
reason
createdAt
}
createdAt
profile {
avatar
description
motto
updatedAt
}
members {
role
member {
alias
authId
}
}
fragment TeamsResponse on teams {
id
name
slug
owner
status {
status
reason
createdAt
}
createdAt
profile {
avatar
description
motto
updatedAt
}
members {
role
member {
alias
authId
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ const ErrorResponse = {
'unique constraint': 'Sorry, already taken! Please create a unique '
}
export const checkGraphQLError = (error) => {
export const checkGraphQLError = error => {
console.log('checkGraphQLError ', ErrorResponse)
if (error.search(/unique constraint/)) {
const field = error.substring(error.indexOf('=') + 1)
@@ -26,14 +26,16 @@ const CreateTeam = () => {
let errors
let loader
if (loading) {
loader = (<Typography variant='caption'>Submitting team...</Typography>)
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>
<Typography key={i} variant='caption'>
{message}
</Typography>
)
})
}
@@ -23,7 +23,7 @@ export const DashTeam = ({ classes, user = null }) => {
owner = JSON.parse(user)
if (isDefined(owner.authId)) authId = owner.authId
} else {
loader = (<Typography variant='caption'>Loading...</Typography>)
loader = <Typography variant='caption'>Loading...</Typography>
}
console.log('DashTeam 2: ', owner, authId)
@@ -51,7 +51,9 @@ export const DashTeam = ({ classes, user = null }) => {
if (error) {
errors = error.graphQLErrors.map(({ message }, i) => {
return (
<Typography key={i} variant='caption'>{message}</Typography>
<Typography key={i} variant='caption'>
{message}
</Typography>
)
})
}
@@ -59,9 +61,10 @@ export const DashTeam = ({ classes, user = null }) => {
if (data.teamsByOwner.length > 0) {
return (
<Grid container spacing={24}>
{!loading && data.teamsByOwner.map(team => (
<DashTeamItem key={team.id} />
))}
{!loading &&
data.teamsByOwner.map(team => (
<DashTeamItem key={team.id} team={team} />
))}
{queryLoader}
{errors}
{loader}
@@ -98,11 +101,9 @@ const getUserOnMount = lifecycle({
}
})
const mapStateToProps = withStateHandlers(
() => ({ user: null }), {
user: ({ user }) => () => ({ user })
}
)
const mapStateToProps = withStateHandlers(() => ({ user: null }), {
user: ({ user }) => () => ({ user })
})
const DashTeamAuthId = compose(
mapStateToProps,
@@ -34,7 +34,7 @@ const styles = theme => ({
}
})
export const DashTeamItem = ({ classes }) => (
export const DashTeamItem = ({ classes, team }) => (
<Grid item>
<Card className={classes.card}>
<div className={classes.cardDetails}>
@@ -44,9 +44,9 @@ export const DashTeamItem = ({ classes }) => (
title='Image title'
/>
<CardContent className={classes.cardContent}>
<Typography variant='headline'>Goodester</Typography>
<Typography variant='headline'>{team.name}</Typography>
<Typography variant='subheading' color='textSecondary'>
09.15.2018
{team.createdAt}
</Typography>
<Typography variant='subheading' paragraph>
Members:6
@@ -66,7 +66,8 @@ export const DashTeamItem = ({ classes }) => (
)
DashTeamItem.propTypes = {
classes: PropTypes.object.isRequired
classes: PropTypes.object.isRequired,
team: PropTypes.object.isRequired
}
export default withStyles(styles)(DashTeamItem)
@@ -0,0 +1,111 @@
import React from 'react'
import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import Paper from '@material-ui/core/Paper'
import Button from '@material-ui/core/Button'
import ButtonBase from '@material-ui/core/ButtonBase'
const styles = theme => ({
layout: {
width: 'auto',
marginLeft: theme.spacing.unit * 2,
marginRight: theme.spacing.unit * 2,
[theme.breakpoints.up(600 + theme.spacing.unit * 2 * 2)]: {
width: 600,
marginLeft: 'auto',
marginRight: 'auto'
}
},
paper: {
marginTop: theme.spacing.unit * 0.1,
marginBottom: theme.spacing.unit * 0.1,
padding: theme.spacing.unit * 2,
[theme.breakpoints.up(600 + theme.spacing.unit * 3 * 2)]: {
marginTop: theme.spacing.unit * 1,
marginBottom: theme.spacing.unit * 1,
padding: theme.spacing.unit * 3
}
},
card: {
display: 'block',
width: '100%'
},
cardDetails: {
display: 'flex',
flex: 1
},
cardContent: {
flex: 1
},
buttonRight: {
justifyContent: 'flex-end'
},
image: {
width: 140,
height: 140
},
img: {
margin: 'auto',
display: 'block',
maxWidth: '100%',
maxHeight: '100%'
}
})
export const TeamsItem = ({ classes, team }) => (
<Grid item>
<main className={classes.layout}>
<Paper className={classes.paper}>
<Grid container spacing={16}>
<Grid item>
<ButtonBase className={classes.image}>
<img
className={classes.img}
alt='complex'
src='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%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
/>
</ButtonBase>
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction='column' spacing={16}>
<Grid item xs>
<Typography variant='headline'>{team.name}</Typography>
<Typography variant='caption' color='textSecondary'>
{team.createdAt}
</Typography>
<Typography variant='caption' paragraph>
Members: 1
</Typography>
</Grid>
<Grid item>
<Typography variant='subheading' color='primary'>
Now recruiting!
</Typography>
</Grid>
</Grid>
<Grid item>
<Button
size='small'
color='primary'
className={classes.buttonRight}
>
Details
</Button>
</Grid>
</Grid>
</Grid>
</Paper>
</main>
</Grid>
)
TeamsItem.propTypes = {
classes: PropTypes.object.isRequired,
team: PropTypes.object.isRequired
}
export default withStyles(styles)(TeamsItem)
@@ -0,0 +1,61 @@
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 GET_ALL_TEAMS_QUERY from '../../../graphql/teams/GetAllTeamsQuery'
import TeamsItem from './TeamsItem'
export const TeamsList = ({ classes }) => (
<Grid item md={12}>
<Query query={GET_ALL_TEAMS_QUERY}>
{({ loading, error, data }) => {
console.log('GET_TEAMS_BY_OWNER: ', loading, error, data)
let errors
let queryLoader
if (error) {
errors = error.graphQLErrors.map(({ message }, i) => {
return (
<Typography key={i} variant='caption'>
{message}
</Typography>
)
})
}
if (!loading && !error) {
if (data.teams.edges.length > 0) {
return (
<Grid container spacing={24}>
{!loading &&
data.teams.edges.map(team => (
<TeamsItem key={team.node.id} team={team.node} />
))}
{queryLoader}
{errors}
</Grid>
)
}
} else {
return (
<Grid container spacing={24}>
<Typography variant='subheading' gutterBottom>
Loading...
</Typography>
{queryLoader}
{errors}
</Grid>
)
}
}}
</Query>
</Grid>
)
TeamsList.propTypes = {
classes: PropTypes.object.isRequired
}
export default TeamsList
+9 -3
View File
@@ -3,8 +3,11 @@ import PropTypes from 'prop-types'
import CssBaseline from '@material-ui/core/CssBaseline'
import Typography from '@material-ui/core/Typography'
import Grid from '@material-ui/core/Grid'
import { withStyles } from '@material-ui/core/styles'
import TeamsList from './components/TeamsList'
const styles = theme => ({
'@global': {
body: {
@@ -28,7 +31,7 @@ const styles = theme => ({
}
})
const Home = ({ classes }) => (
const Teams = ({ classes }) => (
<React.Fragment>
<CssBaseline />
<main className={classes.layout}>
@@ -41,13 +44,16 @@ const Home = ({ classes }) => (
>
Teams
</Typography>
<Grid container spacing={24}>
<TeamsList classes={classes} />
</Grid>
</div>
</main>
</React.Fragment>
)
Home.propTypes = {
Teams.propTypes = {
classes: PropTypes.object.isRequired
}
export default withStyles(styles)(Home)
export default withStyles(styles)(Teams)