Member management forms

This commit is contained in:
Barry Low committed 2018-09-28 01:10:06 -07:00
1 parent a53a3a8cb5
commit caba8bb338
15 files changed
+226 -98

No files matched your search

+1
View File
@@ -65,6 +65,7 @@ type TeamMembers {
}
type TeamMemberStatus {
id: ID! @unique
status: Status @Default(value: INACTIVE)
reason: String
createdAt: DateTime!
+76 -4
View File
@@ -1,5 +1,5 @@
# source: http://localhost:4466
# timestamp: Thu Sep 27 2018 22:50:26 GMT-0700 (Pacific Daylight Time)
# timestamp: Thu Sep 27 2018 23:28:16 GMT-0700 (Pacific Daylight Time)
type AggregateFBStatus {
count: Int!
@@ -1021,14 +1021,17 @@ type Mutation {
updateTeamMembers(data: TeamMembersUpdateInput!, where: TeamMembersWhereUniqueInput!): TeamMembers
updateMember(data: MemberUpdateInput!, where: MemberWhereUniqueInput!): Member
updateFinancialBeings(data: FinancialBeingsUpdateInput!, where: FinancialBeingsWhereUniqueInput!): FinancialBeings
updateTeamMemberStatus(data: TeamMemberStatusUpdateInput!, where: TeamMemberStatusWhereUniqueInput!): TeamMemberStatus
deleteTeam(where: TeamWhereUniqueInput!): Team
deleteTeamMembers(where: TeamMembersWhereUniqueInput!): TeamMembers
deleteMember(where: MemberWhereUniqueInput!): Member
deleteFinancialBeings(where: FinancialBeingsWhereUniqueInput!): FinancialBeings
deleteTeamMemberStatus(where: TeamMemberStatusWhereUniqueInput!): TeamMemberStatus
upsertTeam(where: TeamWhereUniqueInput!, create: TeamCreateInput!, update: TeamUpdateInput!): Team!
upsertTeamMembers(where: TeamMembersWhereUniqueInput!, create: TeamMembersCreateInput!, update: TeamMembersUpdateInput!): TeamMembers!
upsertMember(where: MemberWhereUniqueInput!, create: MemberCreateInput!, update: MemberUpdateInput!): Member!
upsertFinancialBeings(where: FinancialBeingsWhereUniqueInput!, create: FinancialBeingsCreateInput!, update: FinancialBeingsUpdateInput!): FinancialBeings!
upsertTeamMemberStatus(where: TeamMemberStatusWhereUniqueInput!, create: TeamMemberStatusCreateInput!, update: TeamMemberStatusUpdateInput!): TeamMemberStatus!
updateManyTeams(data: TeamUpdateInput!, where: TeamWhereInput): BatchPayload!
updateManyTeamMemberses(data: TeamMembersUpdateInput!, where: TeamMembersWhereInput): BatchPayload!
updateManyMembers(data: MemberUpdateInput!, where: MemberWhereInput): BatchPayload!
@@ -1093,6 +1096,7 @@ type Query {
teamMembers(where: TeamMembersWhereUniqueInput!): TeamMembers
member(where: MemberWhereUniqueInput!): Member
financialBeings(where: FinancialBeingsWhereUniqueInput!): FinancialBeings
teamMemberStatus(where: TeamMemberStatusWhereUniqueInput!): TeamMemberStatus
teamsConnection(where: TeamWhereInput, orderBy: TeamOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): TeamConnection!
teamMembersesConnection(where: TeamMembersWhereInput, orderBy: TeamMembersOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): TeamMembersConnection!
membersConnection(where: MemberWhereInput, orderBy: MemberOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): MemberConnection!
@@ -1333,7 +1337,8 @@ input TeamMembersSubscriptionWhereInput {
node: TeamMembersWhereInput
}
type TeamMemberStatus {
type TeamMemberStatus implements Node {
id: ID!
status: Status
reason: String
createdAt: DateTime!
@@ -1356,6 +1361,7 @@ input TeamMemberStatusCreateInput {
input TeamMemberStatusCreateManyInput {
create: [TeamMemberStatusCreateInput!]
connect: [TeamMemberStatusWhereUniqueInput!]
}
"""An edge in a connection."""
@@ -1368,19 +1374,20 @@ type TeamMemberStatusEdge {
}
enum TeamMemberStatusOrderByInput {
id_ASC
id_DESC
status_ASC
status_DESC
reason_ASC
reason_DESC
createdAt_ASC
createdAt_DESC
id_ASC
id_DESC
updatedAt_ASC
updatedAt_DESC
}
type TeamMemberStatusPreviousValues {
id: ID!
status: Status
reason: String
createdAt: DateTime!
@@ -1425,6 +1432,11 @@ input TeamMemberStatusSubscriptionWhereInput {
node: TeamMemberStatusWhereInput
}
input TeamMemberStatusUpdateDataInput {
status: Status
reason: String
}
input TeamMemberStatusUpdateInput {
status: Status
reason: String
@@ -1432,6 +1444,22 @@ input TeamMemberStatusUpdateInput {
input TeamMemberStatusUpdateManyInput {
create: [TeamMemberStatusCreateInput!]
connect: [TeamMemberStatusWhereUniqueInput!]
disconnect: [TeamMemberStatusWhereUniqueInput!]
delete: [TeamMemberStatusWhereUniqueInput!]
update: [TeamMemberStatusUpdateWithWhereUniqueNestedInput!]
upsert: [TeamMemberStatusUpsertWithWhereUniqueNestedInput!]
}
input TeamMemberStatusUpdateWithWhereUniqueNestedInput {
where: TeamMemberStatusWhereUniqueInput!
data: TeamMemberStatusUpdateDataInput!
}
input TeamMemberStatusUpsertWithWhereUniqueNestedInput {
where: TeamMemberStatusWhereUniqueInput!
update: TeamMemberStatusUpdateDataInput!
create: TeamMemberStatusCreateInput!
}
input TeamMemberStatusWhereInput {
@@ -1443,6 +1471,46 @@ input TeamMemberStatusWhereInput {
"""Logical NOT on all given filters combined by AND."""
NOT: [TeamMemberStatusWhereInput!]
id: ID
"""All values that are not equal to given value."""
id_not: ID
"""All values that are contained in given list."""
id_in: [ID!]
"""All values that are not contained in given list."""
id_not_in: [ID!]
"""All values less than the given value."""
id_lt: ID
"""All values less than or equal the given value."""
id_lte: ID
"""All values greater than the given value."""
id_gt: ID
"""All values greater than or equal the given value."""
id_gte: ID
"""All values containing the given string."""
id_contains: ID
"""All values not containing the given string."""
id_not_contains: ID
"""All values starting with the given string."""
id_starts_with: ID
"""All values not starting with the given string."""
id_not_starts_with: ID
"""All values ending with the given string."""
id_ends_with: ID
"""All values not ending with the given string."""
id_not_ends_with: ID
status: Status
"""All values that are not equal to given value."""
@@ -1517,6 +1585,10 @@ input TeamMemberStatusWhereInput {
createdAt_gte: DateTime
}
input TeamMemberStatusWhereUniqueInput {
id: ID
}
input TeamMembersUpdateInput {
role: Role
email: String
@@ -27,6 +27,7 @@ const TEAMS_CONNECTIONS_FRAGMENT = gql`{
authId
}
status {
id
status
reason
createdAt
+1
View File
@@ -25,6 +25,7 @@ const TEAMS_FRAGMENT = gql`{
authId
}
status {
id
status
reason
createdAt
+1 -1
View File
@@ -26,7 +26,7 @@ type Mutation {
getAzureSAS(teamSlug: String!):String
sendMemberInviteSG(email: String!, teamId: String!): String
confirmMember(token: String!): String
removeMember(email: String!, teamId: String!): String
removeTeamMember(teamId: String!, memberId: String!): String
}
fragment MemberInfo on Member {
+7 -1
View File
@@ -18,17 +18,23 @@ export const GET_ALL_TEAMS_QUERY = gql`
createdAt
profile {
avatar
banner
description
motto
updatedAt
}
members {
role
email
member {
alias
authId
}
status {
id
status
reason
createdAt
}
}
}
}
@@ -16,17 +16,23 @@ export const GET_TEAMS_BY_OWNER = gql`
createdAt
profile {
avatar
banner
description
motto
updatedAt
}
members {
role
email
member {
alias
authId
}
status {
id
status
reason
createdAt
}
}
}
}
@@ -0,0 +1,12 @@
/* eslint-disable no-unused-vars */
import gql from 'graphql-tag'
export const REMOVE_TEAM_MEMBER = gql`
mutation removeTeamMember($teamId: String!, $memberId: String!) {
removeTeamMember(teamId: $teamId, memberId: $memberId) {
id
}
}
`
export default REMOVE_TEAM_MEMBER
@@ -0,0 +1,12 @@
/* eslint-disable no-unused-vars */
import gql from 'graphql-tag'
export const SET_TEAM_MEMBER_ROLE = gql`
mutation setTeamMemberRole($teamId: String!, $memberId: String!, $role: String!) {
setTeamMemberRole(teamId: $teamId, memberId: $memberId, role: $role) {
id
}
}
`
export default SET_TEAM_MEMBER_ROLE
+7 -1
View File
@@ -15,17 +15,23 @@ export const TEAMS_FRAGMENT = gql`
createdAt
profile {
avatar
banner
description
motto
updatedAt
}
members {
role
email
member {
alias
authId
}
status {
id
status
reason
createdAt
}
}
}
`
@@ -28,17 +28,23 @@ const UPDATE_TEAM_PROFILE = gql`
createdAt
profile {
avatar
banner
description
motto
updatedAt
}
members {
role
email
member {
alias
authId
}
status {
id
status
reason
createdAt
}
}
}
}
@@ -11,7 +11,7 @@ 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 REMOVE_TEAM_MEMBER from '../../../graphql/teams/RemoveTeamMemberMutation'
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import { checkGraphQLError } from '../../../utils/graphql-errors'
@@ -58,13 +58,8 @@ export class ManageMemberDelete extends Component {
const { classes, teamId, authId } = this.props
return (
<Mutation
mutation={DELETE_TEAM}
refetchQueries={[
{
query: GET_TEAMS_BY_OWNER,
variables: { authId }
}
]}
mutation={REMOVE_TEAM_MEMBER}
refetchQueries={[{ query: GET_TEAMS_BY_OWNER }]}
>
{(deleteTeam, { loading, error, data }) => {
let errors
@@ -86,7 +81,7 @@ export class ManageMemberDelete extends Component {
})
}
return (
<div>
<React.Fragment>
<Button
size='small'
color='primary'
@@ -123,7 +118,8 @@ export class ManageMemberDelete extends Component {
this.handleSubmit(
e,
deleteTeam,
teamId
teamId,
authId
)
}}
color='primary'
@@ -133,16 +129,16 @@ export class ManageMemberDelete extends Component {
</DialogActions>
</div>
</Dialog>
</div>
</React.Fragment>
)
}}
</Mutation>
)
}
async handleSubmit (e, deleteTeam, teamId) {
async handleSubmit (e, deleteTeam, teamId, memberId) {
e.preventDefault()
await deleteTeam({ variables: { teamId } })
await deleteTeam({ variables: { teamId, memberId } })
this.setState({ open: false })
}
}
@@ -150,7 +146,7 @@ export class ManageMemberDelete extends Component {
ManageMemberDelete.propTypes = {
classes: PropTypes.object.isRequired,
teamId: PropTypes.string.isRequired,
authId: PropTypes.string.isRequired
authId: PropTypes.string
}
export default withStyles(styles)(ManageMemberDelete)
@@ -10,8 +10,10 @@ 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 TextField from '@material-ui/core/TextField'
import MenuItem from '@material-ui/core/MenuItem'
import DELETE_TEAM from '../../../graphql/teams/DeleteTeamMutation'
import SET_TEAM_MEMBER_ROLE from '../../../graphql/teams/SetTeamMemberRoleMutation'
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import { checkGraphQLError } from '../../../utils/graphql-errors'
@@ -27,6 +29,11 @@ const styles = theme => ({
}
})
const roles = [
{ role: 'Admin' },
{ role: 'Member' }
]
export class ManageMemberRole extends Component {
constructor (props) {
super(props)
@@ -37,7 +44,8 @@ export class ManageMemberRole extends Component {
this.handleSubmit = this.handleSubmit.bind(this)
this.state = {
open: false
open: false,
role: ''
}
}
@@ -58,15 +66,10 @@ export class ManageMemberRole extends Component {
const { classes, teamId, authId } = this.props
return (
<Mutation
mutation={DELETE_TEAM}
refetchQueries={[
{
query: GET_TEAMS_BY_OWNER,
variables: { authId }
}
]}
mutation={SET_TEAM_MEMBER_ROLE}
refetchQueries={[{ query: GET_TEAMS_BY_OWNER }]}
>
{(deleteTeam, { loading, error, data }) => {
{(setTeamMemberRole, { loading, error, data }) => {
let errors
let loader
if (loading) {
@@ -86,7 +89,7 @@ export class ManageMemberRole extends Component {
})
}
return (
<div>
<React.Fragment>
<Button
size='small'
color='primary'
@@ -108,6 +111,17 @@ export class ManageMemberRole extends Component {
<Typography variant='subheading'>
Admin members can approve new team members, send team invitations, and remove team members.
</Typography>
<TextField
select
label='Team Role'
value={this.state.role}
onChange={(e) => this.setState({ role: e.target.value })}
fullWidth
>
{roles.map(role => (
<MenuItem key={role.role} value={role.role}>{role.role}</MenuItem>
))}
</TextField>
{loader}
{errors}
</DialogContent>
@@ -119,8 +133,9 @@ export class ManageMemberRole extends Component {
onClick={e => {
this.handleSubmit(
e,
deleteTeam,
teamId
setTeamMemberRole,
teamId,
authId
)
}}
color='primary'
@@ -130,16 +145,17 @@ export class ManageMemberRole extends Component {
</DialogActions>
</div>
</Dialog>
</div>
</React.Fragment>
)
}}
</Mutation>
)
}
async handleSubmit (e, deleteTeam, teamId) {
async handleSubmit (e, setTeamMemberRole, teamId, authId) {
e.preventDefault()
await deleteTeam({ variables: { teamId } })
const role = this.state.role
await setTeamMemberRole({ variables: { teamId, memberId: authId, role: role } })
this.setState({ open: false })
}
}
@@ -2,7 +2,6 @@ import React from 'react'
import PropTypes from 'prop-types'
import Grid from '@material-ui/core/Grid'
import CardMedia from '@material-ui/core/CardMedia'
import Typography from '@material-ui/core/Typography'
import ManageMemberDelete from './ManageMemberDelete'
@@ -12,38 +11,35 @@ import { MessageCard } from '../../common/'
export const ManageMembersItem = ({ classes, member, teamId, authId }) => {
console.log('ManageMembersItem', member)
let profile = null
let email = null
let memberStatus = null
if (member.member !== null) {
profile = member.member
}
let avatar = null
if (member.profile !== undefined && member.profile !== null && member.profile.avatar !== undefined && member.profile.avatar !== 'a') {
avatar = member.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%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
if (member.member === null && member.email !== null) {
email = member.email
}
if (profile !== null) {
if (member.status.length > 0) memberStatus = member.status
if (profile !== null || email !== null) {
return (
<Grid container className={classes.memberContainer}>
<Grid item xs={1}>
<CardMedia
className={classes.cardMemberMedia}
image={avatar}
title={member.name}
/>
</Grid>
<Grid item xs={4}>
<Typography gutterBottom variant='headline' component='h2'>
{profile.alias}
<Typography gutterBottom variant='subheading' component='h2' align='left' >
{profile !== null ? profile.alias : email}
</Typography>
</Grid>
<Grid item xs={4}>
<Typography variant='caption' color='textSecondary'>
{member.role} | Member since:
<Typography color='textSecondary' variant='body2' component='h4' align='left' >
{email !== null ? `${memberStatus[memberStatus.length - 1].status} | Sent: ${memberStatus[memberStatus.length - 1].createdAt}` : `${member.role} | Member since: `}
</Typography>
</Grid>
<Grid item xs={3}>
<ManageMemberRole teamId={teamId} authId={authId} />
<ManageMemberDelete teamId={teamId} authId={authId} />
<Grid item xs={4}>
{ profile !== null && member.role !== 'OWNER' && (
<ManageMemberRole teamId={teamId} authId={profile !== null ? profile.authId : null} className={classes.buttonRight} />
)}
{(email !== null || member.role !== 'OWNER') && (
<ManageMemberDelete teamId={teamId} authId={profile !== null ? profile.authId : null} email={email !== null ? email : null} className={classes.buttonRight} />
)}
</Grid>
</Grid>
)
@@ -50,8 +50,8 @@ const styles = theme => ({
justifyContent: 'flex-start'
},
memberContainer: {
margin: 40,
padding: 12
margin: 10,
padding: 6
}
})
@@ -66,43 +66,40 @@ export const ManageMembersTeamItem = ({ classes, team, authId }) => {
if (team.members.length > 0) {
return (
<React.Fragment>
{ team.members.map(member => {
console.log('ManageMembersTeamItem: ', member)
return (
<Grid item xs={12} key={`${team.id}-${member.member.alias}`}>
<Card className={classes.card}>
<div className={classes.cardDetails}>
<CardContent className={classes.cardContent}>
<Grid container>
<Grid item xs={2}>
<CardMedia
className={classes.cardMedia}
image={avatar}
title={team.name}
/>
</Grid>
<Grid item xs={9}>
<Typography gutterBottom variant='headline' component='h2'>
{team.name}
</Typography>
</Grid>
<Grid item xs={1}>
<InviteMemberDialog teamId={team.id} />
</Grid>
</Grid>
<ManageMembersItem
member={member}
teamId={team.id}
authId={authId}
classes={classes}
<Grid item xs={12} key={team.id}>
<Card className={classes.card}>
<div className={classes.cardDetails}>
<CardContent className={classes.cardContent}>
<Grid container>
<Grid item xs={2}>
<CardMedia
className={classes.cardMedia}
image={avatar}
title={team.name}
/>
</CardContent>
</div>
</Card>
</Grid>
)
})
}
</Grid>
<Grid item xs={9}>
<Typography gutterBottom variant='headline' component='h2'>
{team.name}
</Typography>
</Grid>
<Grid item xs={1}>
<InviteMemberDialog teamId={team.id} />
</Grid>
</Grid>
{team.members.length > 0 && team.members.map((member, index) => (
<ManageMembersItem
member={member}
teamId={team.id}
authId={authId}
classes={classes}
key={`${team.id}-${index}`}
/>
))}
</CardContent>
</div>
</Card>
</Grid>
</React.Fragment>
)
} else {