diff --git a/api/database/datamodel.graphql b/api/database/datamodel.graphql index 59a2226f6..9c07196ef 100644 --- a/api/database/datamodel.graphql +++ b/api/database/datamodel.graphql @@ -65,6 +65,7 @@ type TeamMembers { } type TeamMemberStatus { + id: ID! @unique status: Status @Default(value: INACTIVE) reason: String createdAt: DateTime! diff --git a/api/src/generated/prisma.graphql b/api/src/generated/prisma.graphql index 2ecbd89d3..1dade0729 100644 --- a/api/src/generated/prisma.graphql +++ b/api/src/generated/prisma.graphql @@ -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 diff --git a/api/src/graphql/TeamsConnectionsFragment.js b/api/src/graphql/TeamsConnectionsFragment.js index a7494d8c0..931d3ac4a 100644 --- a/api/src/graphql/TeamsConnectionsFragment.js +++ b/api/src/graphql/TeamsConnectionsFragment.js @@ -27,6 +27,7 @@ const TEAMS_CONNECTIONS_FRAGMENT = gql`{ authId } status { + id status reason createdAt diff --git a/api/src/graphql/TeamsFragment.js b/api/src/graphql/TeamsFragment.js index 95a111aff..71069f501 100644 --- a/api/src/graphql/TeamsFragment.js +++ b/api/src/graphql/TeamsFragment.js @@ -25,6 +25,7 @@ const TEAMS_FRAGMENT = gql`{ authId } status { + id status reason createdAt diff --git a/api/src/schema.graphql b/api/src/schema.graphql index 6b835e9ec..b6d7c40e7 100644 --- a/api/src/schema.graphql +++ b/api/src/schema.graphql @@ -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 { diff --git a/client/src/graphql/teams/GetAllTeamsQuery.js b/client/src/graphql/teams/GetAllTeamsQuery.js index 0bd9ed522..aa484f1f8 100644 --- a/client/src/graphql/teams/GetAllTeamsQuery.js +++ b/client/src/graphql/teams/GetAllTeamsQuery.js @@ -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 + } } } } diff --git a/client/src/graphql/teams/GetTeamsByOwnerQuery.js b/client/src/graphql/teams/GetTeamsByOwnerQuery.js index 7f10b0b07..c38c6ebff 100644 --- a/client/src/graphql/teams/GetTeamsByOwnerQuery.js +++ b/client/src/graphql/teams/GetTeamsByOwnerQuery.js @@ -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 + } } } } diff --git a/client/src/graphql/teams/RemoveTeamMemberMutation.js b/client/src/graphql/teams/RemoveTeamMemberMutation.js new file mode 100644 index 000000000..2abf62acd --- /dev/null +++ b/client/src/graphql/teams/RemoveTeamMemberMutation.js @@ -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 diff --git a/client/src/graphql/teams/SetTeamMemberRoleMutation.js b/client/src/graphql/teams/SetTeamMemberRoleMutation.js new file mode 100644 index 000000000..283315275 --- /dev/null +++ b/client/src/graphql/teams/SetTeamMemberRoleMutation.js @@ -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 diff --git a/client/src/graphql/teams/Teams.js b/client/src/graphql/teams/Teams.js index ce0a6f36b..4a0c84d37 100644 --- a/client/src/graphql/teams/Teams.js +++ b/client/src/graphql/teams/Teams.js @@ -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 + } } } ` diff --git a/client/src/graphql/teams/UpdateTeamProfileMutation.js b/client/src/graphql/teams/UpdateTeamProfileMutation.js index 08b229b98..39feabf8d 100644 --- a/client/src/graphql/teams/UpdateTeamProfileMutation.js +++ b/client/src/graphql/teams/UpdateTeamProfileMutation.js @@ -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 + } } } } diff --git a/client/src/views/dashboard/components/ManageMemberDelete.js b/client/src/views/dashboard/components/ManageMemberDelete.js index 4419aa55f..b3ee25d1b 100644 --- a/client/src/views/dashboard/components/ManageMemberDelete.js +++ b/client/src/views/dashboard/components/ManageMemberDelete.js @@ -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 ( {(deleteTeam, { loading, error, data }) => { let errors @@ -86,7 +81,7 @@ export class ManageMemberDelete extends Component { }) } return ( -
+
- + ) }}
) } - 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) diff --git a/client/src/views/dashboard/components/ManageMemberRole.js b/client/src/views/dashboard/components/ManageMemberRole.js index 2e19bf48c..6edf5ddf1 100644 --- a/client/src/views/dashboard/components/ManageMemberRole.js +++ b/client/src/views/dashboard/components/ManageMemberRole.js @@ -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 ( - {(deleteTeam, { loading, error, data }) => { + {(setTeamMemberRole, { loading, error, data }) => { let errors let loader if (loading) { @@ -86,7 +89,7 @@ export class ManageMemberRole extends Component { }) } return ( -
+
- + ) }}
) } - 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 }) } } diff --git a/client/src/views/dashboard/components/ManageMembersItem.js b/client/src/views/dashboard/components/ManageMembersItem.js index 4d5ea5597..1e082c8c5 100644 --- a/client/src/views/dashboard/components/ManageMembersItem.js +++ b/client/src/views/dashboard/components/ManageMembersItem.js @@ -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 ( - - - - - {profile.alias} + + {profile !== null ? profile.alias : email} - - {member.role} | Member since: + + {email !== null ? `${memberStatus[memberStatus.length - 1].status} | Sent: ${memberStatus[memberStatus.length - 1].createdAt}` : `${member.role} | Member since: `} - - - + + { profile !== null && member.role !== 'OWNER' && ( + + )} + {(email !== null || member.role !== 'OWNER') && ( + + )} ) diff --git a/client/src/views/dashboard/components/ManageMembersTeamItem.js b/client/src/views/dashboard/components/ManageMembersTeamItem.js index 2969aaba2..6d0731513 100644 --- a/client/src/views/dashboard/components/ManageMembersTeamItem.js +++ b/client/src/views/dashboard/components/ManageMembersTeamItem.js @@ -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 ( - { team.members.map(member => { - console.log('ManageMembersTeamItem: ', member) - return ( - - -
- - - - - - - - {team.name} - - - - - - - + +
+ + + + - -
-
- - ) - }) - } + + + + {team.name} + + + + + + + {team.members.length > 0 && team.members.map((member, index) => ( + + ))} +
+
+
+
) } else {