Task management application built with React/Redux, Ruby on Rails, and PostgreSQL.
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
app
bin
config
db
frontend
lib
public
readme
test
vendor
.gitignore
Gemfile
Gemfile.lock
README.md
Rakefile
config.ru
package.json
webpack.config.js

README.md

README

https://remember-to-check-in.herokuapp.com/#/

Remember to Check In is a web application that is clone of Remember the Milk (www.rememberthemilk.com). The application allows users to keep track of their todo lists and tasks, including their due dates. A search functionality is also available for users to search through all the tasks. The technology stack of this project includes Ruby on Rails, postgreSQL, and React/Redux.

Detailed of application design, including database tables and component hierarchy can be viewed in the wiki tab.

Backend Features and Implementation

Database Tables

Three tables are created on the backend: users, lists, and tasks. Users table stores the user's credentials, including first name, last name, email, username, and password digest. The list table stores list title and user_id, while the tasks table stores title due_dates list_id and whether the task has been completed or not.

Database indexing was added to all foreign keys for efficient look ups. A unique index was added to user_id and list title as well to ensure that a user cannot create a list with the same title.

add_index :lists, [:title, :user_id], :unique => true

Models

On the model level, because tasks belong to list, and lists belong to users, there is a has many association where the user has many lists and list has many tasks. Task also has a has one user through "list" association (this will be used to verify that a task belongs to the user when an API request is issued from the front end). A dependent destroy is also added to each of these associations to ensure that when a user is destroyed, all the lists belonging to the user are destroyed, and when a list is destroyed, all the tasks belonging to the list are destroyed as well.

In addition, model level validation was added to ensure that all fields need to be present, that emails are unique, and password has to be at least 6 or more characters.

validates :username, :email, :first_name, :last_name, :password_digest, :session_token, presence: true
validates :username, :email, uniqueness: true
validates :password, length: {minimum: 6, allow_nil: true}

User authentication

User authentication process was was created without using an external library, only BCrypt was used to hash the user supplied password. In order to check if a user is logged in, the cookie's session token is compared to one that is stored in the database; similarly, when logging the user in, the session token of the user attempting to log in is reset to ensure that the session token stored in the back end is same as the session token stored in the cookie.

signup Users can sign up or login. If credentials are invalid, an error message will appear. Users are also able to do demo login.

Controllers

There were five main controllers: application, users, sessions, lists and tasks. Each of the controller responded with a JSON. Jbuilder was used to pre-process and manipulate results returned from the database before returning to the front end. This is done so that it becomes easier to normalized the the state inside the redux store. In addition, three crucial methods were added to the application controllers: require_login, verify_list_belongs_to_user, and verify tasks_belongs_to_user. These methods were added to ensure that the user needs to be logged in to make API requests, and that these requests are to only lists and tasks that belong to the user.

In addition, each time a user signs up the create controller in the users controller will also create a default 'welcome list' with prepopulated tasks for the user. This 'welcome list' contains a brief guide on how to work with the website (add/edit/remove tasks and lists and search).

Frontend Features and Implementation

Redux Cycle

Functions that make AJAX requests have been created for sessions (to sign user up, sign in and sign out), lists and tasks (create, remove, update, read). Actions have been separated out into two big buckets, entities actions and ui actions. Entities actions contain functions which trigger the ajax requests, including session actions, lists actions and tasks actions, while ui actions are purely actions that are triggered to change the information in the store about what is currently displayed/not displayed. Similarly, the reducer has been structured to include three main slices: entities, session and ui. Thunk has been used as installed as the middleware in the store.

const rootReducer = combineReducers({
  entities,
  session,
  ui
});

React Components

Lists are rendered as a side bar on the page. As mentioned above, by default each user will have a 'Welcome List' which they cannot remove or rename. When lists are getting populated in the sidebar during the re-rendering phase, each list title is checked if it has the title 'Wecome List', if it does, the edit and remove button is not shown. In addition, there is also a safeguard at the backend in the list controllers under edit and destroy action to check if the title is 'Welcome List' to prevent the user from making manual ajax requests to edit or remove. In addition the user cannot create a list with the same name as well. There is modal for creating, updating, and removing list. The implementation of the modal is discussed below.

list Users are able to create, rename, and remove lists. A modal appears for each of these actions.

Task is the most involved component since it is further divided into three big components: TaskIndex, TaskDetail, and TaskEdit. TaskIndex component is rendered in middle part of the page, next to the list side bar. It renders all the incomplete or complete tasks of a list, depending on which tab the user selects. Underhood I have a TaskIndexContainer that retrieves all the tasks belonging to the list from the store, and that is passed into another function to return back two sets of arrays, completed and incompleted. TaskDetail page is rendered by default on the right of task index. TaskDetail shows the total number of tasks and completed tasks. The number of tasks, completed and incompleted are passed down from the task index page. Task edit is shown when the user presses on a task. The task edit page will replace/slide on top of task detail page. Behind the scene, every time a user presses on a task item, a uiDisplayEdit action is fired to update the uiDisplayEdit to true. This causes a re-render on the TaskIndex page to show the TaskEdit next to it, not the task detail. Same logic applies for when the user presses the close button on the task edit page, a uiDisplayEdit action to update the uiDisplayEidt to false. Task edit page allows users to set the due date, change name of tasks and remove task.

task Users are able to create, rename, and remove tasks. In addition, users can set the due dates and also mark a task complete.

The Search component fires off a search query to the backend after the user presses enter on the search bar. The search is done in the backend using an active record query, as shown in the code snippet below. The selected tasks are returned to the front end and stored in the uiSearchedTasks state slice, which are then displayed to the user. Like the TaskIndex, tasks displayed on the search page are divided to incomplete and complete using the same method. Each task also has a link to its TaskIndex page.

search Users can search for tasks across all lists. Tasks include both complete and incomplete.

Modal

A Modal component is displayed when the user creates, edits, remove or updates the list. A ui slice of state has a modalDisplay property that stores null or a string of form to display (ex: 'addList', 'removeList', etc..). When a user triggers any of the aforementioned actions, an action is fired to change the modalDisplay property. Depending on the string, a predefined form will be shown. The modal has a CSS div that covers the entire page with a z-index of 1000 and form for the user. After user submits the form or cancels, an action is triggerred to remove the modal.

CSS

CSS grid, CSS animation, and React flipmove were used heavily to enhance the user interface and experience.