We-Resist Project Update: Adding Administrator Role and Actions

in utopian-io •  6 years ago  (edited)

Repository

https://github.com/r351574nc3/we-resist-dashboard

New Features

Administrator Role and Member Management Actions

Added a new role field to member information. This new role field just has Administrator for now. More roles will be added in the future that are interactive with the Discord channel. For now, there is just Administrator. It's main function is to allow through the user interface moderators and administrators the ability to remove members from the community that are no longer participating. Members that are no longer participating are using bot resources (votes) without making any contribution to the community. It's not always their fault. Due diligence is the burden of moderators. This is just a tool to help moderators handle that.

With this new database field, we're able to adjust the user interface by adding new columns that describe a user's activity to determine if the member is contributing/participating or not.

Additionally, an action to remove the member has been added as a button next to each member record in the user interface.

Details and Changes


diff --git a/src/actions/auth.js b/src/actions/auth.js
index d365136..95636b8 100644
--- a/src/actions/auth.js
+++ b/src/actions/auth.js
@@ -22,4 +22,12 @@ export const logout = data => dispatch => {
         payload: data
     }
     dispatch(action)
+}
+
+export const assign_role = data => dispatch => {
+    const action = {
+        type: constants.ROLE_ASSIGNED,
+        payload: data
+    }
+    dispatch(action)
 }
diff --git a/src/actions/community.js b/src/actions/community.js
index bf828eb..16cb41c 100644
--- a/src/actions/community.js
+++ b/src/actions/community.js
@@ -53,4 +53,12 @@ export const change_threshold = data => dispatch => {
         value: data
     }
     dispatch(action)    
+}
+
+export const remove_member = data => dispatch => {
+    const action = {
+        type: constants.REMOVE_MEMBERS,
+        value: data
+    }
+    dispatch(action)    
 }

Actions are added for removing members and for assigning the role. This will generate events which get handled by reducers and selectors for updating the user interface from the change

diff --git a/src/constants/auth.js b/src/constants/auth.js
index d7ae8d5..f8861f7 100644
--- a/src/constants/auth.js
+++ b/src/constants/auth.js
@@ -4,3 +4,4 @@ export const USER_LOGGED_OUT = 'USER_LOGGED_OUT'
 export const AUTH_INITIATED = 'auth/AUTH_INITIATED';
 export const AUTH_SUCCESS = 'auth/AUTH_SUCCESS';
 export const AUTH_FAIL = 'auth/AUTH_FAIL';
+export const ROLE_ASSIGNED = 'auth/ROLE_ASSIGNED';
diff --git a/src/constants/community.js b/src/constants/community.js
index 79a9ec5..7f0bf65 100644
--- a/src/constants/community.js
+++ b/src/constants/community.js
@@ -5,3 +5,4 @@ export const UPVOTE_CHANGED = 'community/UPVOTE_CHANGED';
 export const DOWNVOTE_CHANGED = 'community/DOWNVOTE_CHANGED';
 export const THRESHOLD_CHANGED = 'community/THRESHOLD_CHANGED';
 export const MEMBERS_UPDATED = 'community/MEMBERS_UPDATED';
+export const REMOVE_MEMBERS = 'community/REMOVE_MEMBERS';

Constants were added to make the code more readable

diff --git a/src/pages/community/Members.js b/src/pages/community/Members.js
index 5cb7cf3..f4c383f 100644
--- a/src/pages/community/Members.js
+++ b/src/pages/community/Members.js
@@ -3,6 +3,9 @@ import Avatar from "@atlaskit/avatar";
 import { connect } from 'react-redux'
 import ContentWrapper from '../../components/ContentWrapper'
 import PageTitle from '../../components/PageTitle'
+import Button, { ButtonGroup } from '@atlaskit/button'
+import TextField from '@atlaskit/field-text'
+import PageHeader from '@atlaskit/page-header'
 import DynamicTable from '@atlaskit/dynamic-table'
 import styled from 'styled-components';
 import selectors from '../../selectors'
@@ -44,6 +47,7 @@ class Members extends Component {
 
   componentDidMount () {
     const members_url = '/api/community/member_list'
+    this.props.assign_role('Administrator')
     fetch(members_url)
       .then((response) => response.json())
       .then((members) => {
@@ -78,7 +82,35 @@ class Members extends Component {
                 shouldTruncate: true,
                 isSortable: true
               },
-            ],
+              this.props.isAdmin ? {
+                key: 'isActive',
+                content: 'Active?',
+                shouldTruncate: true,
+                isSortable: true
+              } : {},
+              this.props.isAdmin ? {
+                key: 'threshold',
+                content: 'Threshold',
+                shouldTruncate: true,
+                isSortable: false        
+              } : {},
+              this.props.isAdmin ? {
+                key: 'downvote',
+                content: 'DV Percentage',
+                shouldTruncate: true,
+                isSortable: false        
+              } : {},
+              this.props.isAdmin ? {
+                key: 'upvote',
+                content: 'UV Percentage',
+                shouldTruncate: true,
+                isSortable: false
+              } : {},
+              this.props.isAdmin ? { 
+                key: 'actions', 
+                content: (<Button onClick={() => this.props.remove_members()}>Delete</Button>) 
+              } : {}
+            ]
           }
         })
       })
@@ -88,6 +120,39 @@ class Members extends Component {
   }
     
   render () {
+    if (this.props.isAdmin) {
+      this.head.cells.push({
+        key: 'isActive',
+        content: 'Active?',
+        shouldTruncate: true,
+        isSortable: true
+      })
+      this.head.cells.push({
+        key: 'threshold',
+        content: 'Threshold',
+        shouldTruncate: true,
+        isSortable: false
+      })
+      this.head.cells.push({
+        key: 'downvote',
+        content: 'DV Percentage',
+        shouldTruncate: true,
+        isSortable: false
+      })
+      this.head.cells.push({
+        key: 'upvote',
+        content: 'UV Percentage',
+        shouldTruncate: true,
+        isSortable: false
+      })
+      this.head.cells.push({
+        key: 'actions',
+        content: 'Actions',
+        shouldTruncate: true,
+        isSortable: false
+      })
+    }
+
     return (
       <ContentWrapper>
         <PageTitle>Members</PageTitle>
@@ -112,11 +177,14 @@ class Members extends Component {
 
 const mapStateToProps = (state) => {
   const members = selectors.community.selectMembers(state)
-  return { members }
+  const isAdmin = selectors.auth.selectAdmin(state)
+  return { members, isAdmin }
 }
 
 const mapDispatchToProps = {
-  update_members: actions.community.update_members
+  update_members: actions.community.update_members,
+  remove_member: actions.community.remove_member,
+  assign_role: actions.auth.assign_role
 }
 
 export default connect(mapStateToProps, mapDispatchToProps)(Members)

Changes to the members component to access redux state for role information. Also added the necessary fields for when
a user is an administrator.

diff --git a/src/reducers/auth.js b/src/reducers/auth.js
index 628c6ea..2f71134 100644
--- a/src/reducers/auth.js
+++ b/src/reducers/auth.js
@@ -6,7 +6,8 @@ const initialState = {
   isLoading: false,
   isAuthenticated: false,
   user: null,
-  preferences: null
+  preferences: null,
+  role: null
 }
 
 function fetch_preferences(user) {
@@ -27,13 +28,9 @@ export default (state = initialState, { type, payload }) => {
     case constants.auth.AUTH_INITIATED:
       return state
     case constants.auth.AUTH_SUCCESS:
-      return { 
-        data: payload, 
-        isLoading: false, 
-        isAuthenticated: true, 
-        user: payload,
-        preferences: fetch_preferences(payload)
-      }
+      return { ...state, isAuthenticated: true, data: payload, user: payload, preferences: fetch_preferences(payload) }
+    case constants.auth.ROLE_ASSIGNED:
+      return { ...state, isAdministrator: true }
     case constants.auth.AUTH_FAIL:
       return initialState
     default:
diff --git a/src/reducers/community.js b/src/reducers/community.js
index 5d76552..41b771c 100644
--- a/src/reducers/community.js
+++ b/src/reducers/community.js
@@ -46,6 +46,10 @@ export default (state = INITIAL_STATE, action) => {
                     threshold: action.value
                 } 
             }
+        case constants.REMOVE_MEMBERS:
+            return { ...state, 
+                members: action.value
+            }
         default:
             return state
   }

Here I added redux reducers to handle member removal and for role assignment to set state on whether the user is an admin or not

diff --git a/src/selectors/auth.js b/src/selectors/auth.js
index 4ab2978..0dcce0d 100644
--- a/src/selectors/auth.js
+++ b/src/selectors/auth.js
@@ -1,4 +1,5 @@
 export default {
     selectAuthenticated: state => state.auth.isAuthenticated,
+    selectAdmin: state => state.auth.isAdministrator,
     selectUser: state => state.auth.user
 }

Here I added administrator state fields for redux

Pull Requests

https://github.com/r351574nc3/we-resist-dashboard/pull/4

GitHub Account

https://github.com/r351574nc3

Please Vote Your Favorite Witness...Me!

Vote for r351574nc3

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Thanks for the contribution, @r351574nc3!

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Sweet! Thanks @amosbastian

Hey @r351574nc3
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Wooohoo!

Finally! Look forward to more features and improvements.