TaskTracker is a team communication application that unifies team objectives and improves workflow.
- Full CRUD functionalities for Users, Groups, Tasks, and Messages. Users can also designate tasks to other users in their groups.
- Anonymous messaging to call out people that aren't getting things done.
- Tracking for each group member to see their completed and upcoming tasks.
TaskTracker is a collaborative project utilizing the MERN stack (MongoDB, Express, React, Node.js).
Other technologies used:
- Websockets was utilized to implement the messaging service.
- The library Materialize rendered frontend styling and modal views.
- Axios allowed for API calls for communication between frontend and backend.
Chat messages are handled and rendered in different ways, depending on whether they are: your own or someone else's messages, anonymous or public, or part of a group of messages from the same person.
renderMessages(){const{ users }=this.props;const{ messages }=this.state;if(!messages)return;letconversation=[];letauthorName;letprevId="";for(leti=messages.length-1;i>=0;i--){letauthor=users.filter(user=>user.id===messages[i].author);authorName=author[0].username;if(messages[i].author===this.props.currentUser.id){// message sent by current userconversation.unshift(<liclassName="own-message"key={messages[i]._id}><divclassName="message"><span>{messages[i].body}</span></div></li>);prevId="";}elseif(messages[i].anon){// message sent anonymously so username is set to anonconversation.unshift(<liclassName="other-message"key={messages[i]._id}><div><iid="pf"className="fas fa-question-circle"/></div><divclassName="message-box"><divclassName="message"><span>{messages[i].body}</span></div><divclassName="author">Anonymous</div></div></li>);prevId="";}elseif(messages[i].author===prevId){// messages sent by previous message sender so username and picture arent shown againconversation.unshift(<liclassName="other-message"key={messages[i]._id}><divclassName="message-box"id="pf-placeholder"><divclassName="message"><span>{messages[i].body}</span></div></div></li>);}else{conversation.unshift(<liclassName="other-message"key={messages[i]._id}><div><iid="pf"className="fas fa-user-circle"/></div><divclassName="message-box"><divclassName="message"><span>{messages[i].body}</span></div><divclassName="author">{authorName}</div></div></li>);prevId=messages[i].author;}}returnconversation;}Tasks must be assigned to a user and a group. Both of these are filtered such that the available options in the task creation form are relevant (e.g. only groups that the current user belongs to) and sorted alphabetically.
constmapStateToProps=(state)=>({users: Object.values(state.entities.users).filter(user=>user.username).sort((a,b)=>{if(a.username<b.username)return-1;elsereturn1;}),groups: Object.values(state.entities.groups).filter(group=>group.name).sort((a,b)=>{if(a.name<b.name)return-1;elsereturn1;}),currentUserId: state.session.id});let{ users, groups, currentUserId }=this.props;letuserOptions=[];users.forEach(user=>{userOptions.push({label: user.username,value: user.id});});letgroupOptions=[];constgroupFilter=selectUserGroups(currentUserId,groups);groupFilter.forEach(group=>{groupOptions.push({label: group.name,value: group._id});});- Transition to React Native mobile application
- Image uploading for Users, Groups, Messaging
- Task Statistics
- Task Penalties