CSC/ECE 517 Spring 2024 - E2429 Reimplement student task list

From Expertiza_Wiki
Jump to navigation Jump to search

Introduction

The Expertiza application is a collaborative platform used by students and instructors for managing assignments, peer reviews, and feedback. The current student task list interface lacks responsiveness, usability, and performance. The objective is to reimplement the frontend of the student task list using React JS and TypeScript. This reimplementation aims to enhance the user experience, improve task management, and optimize performance.

Project Requirements

The project will focus on the following features:

  1. Dynamic Task Table: Display a table listing student assignments. columns: Assignment name, course, topic, current stage, review grade, badges, stage deadline, and publishing rights.Implement sorting and filtering functionalities for efficient task navigation.
  2. Responsive Design: Prioritize accessibility and user-friendly layouts.
  3. Lazy Loading: Optimize performance by loading content only when necessary.Improve page load times for a smoother user experience.

Dummy Data

Interfaces

The interfaces were designed as a prototype for testing purposes. The future team working on the backend needs to modify it as needed.

The implementation can be found here

Duty and StudentsTeamedWith is for the side box.

Revision's purpose is undefined for now, so leave it empty, the future team should delete it if it is proved to be redundant.

IStudentTask is for the main table of student task.

export interface Duty {
  name: string;
  dueDate: string;
}

export interface Revision {

}

export interface StudentsTeamedWith {
  [semester: string]: string[];
}


// Interface for matching columns to assignment table columns
export interface IStudentTask {
  name: string;
  course_name: string;
  topic: string;
  current_stage: string;
  review_grade: {
    comment: string;
  };
  has_badge: boolean;
  stage_deadline: Date
  publishing_rights: boolean

}


JSON File

JSON File are also created for the purpose of testing, the future team should delete this file if the data can be successfully retrieved from the database.

JSON File can be found here

{
    "assignments": [
        {
            "name": "Assignment 1",
            "course_name": "CSC 517",
            "topic": "Ruby",
            "current_stage": "in progress",
            "review_grade": {
                "comment": "3/5"
            },
            "has_badge": false,
            "stage_deadline": "3/18",
            "publishing_rights": true
        },
        {
            "name": "Assignment 2",
            "course_name": "CSC 517",
            "topic": "Rails",
            "current_stage": "in progress",
            "review_grade": "N/A",
            "has_badge": true,
            "stage_deadline": "3/18",
            "publishing_rights": true
        },
        {
            "name": "Assignment 3",
            "course_name": "CSC 517",
            "topic": "Git",
            "current_stage": "in progress",
            "review_grade": "N/A",
            "has_badge": true,
            "stage_deadline": "3/18",
            "publishing_rights": false
        },
        {
            "name": "Assignment 1",
            "course_name": "CSC 522",
            "topic": "AI",
            "current_stage": "in progress",
            "review_grade": "N/A",
            "has_badge": false,
            "stage_deadline": "3/25",
            "publishing_rights": true
        },
        {
            "name": "Assignment 2",
            "course_name": "CSC 522",
            "topic": "Random Forest",
            "current_stage": "finished",
            "review_grade": "N/A",
            "has_badge": false,
            "stage_deadline": "3/28",
            "publishing_rights": true
        }
    ],
    "duties": [
        {
            "name": "CSC517-Assignment 1",
            "dueDate": "2024-03-18"
        },
        {
            "name": "CSC517-Assignment 2",
            "dueDate": "2024-03-18"
        },
        {
            "name": "CSC517-Assignment 3",
            "dueDate": "2024-03-18"
        },
        {
            "name": "CSC522-Assignment 1",
            "dueDate": "2024-03-25"
        },
        {
            "name": "CSC522-Assignment 2",
            "dueDate": "2024-03-28"
        }
    ],
    "revisions": [

    ],
    "studentsTeamedWith": {
        "CSC540, Fall 2023": ["classmate one", "classmate two", "classmate three", "classmate four"],
        "CSC515, Spring 2024": ["classmate five", "classmate six", "classmate seven"]
    }
}

Changes

Student Task Page

Dummy Data

The fetching of the data and rendering of the table slightly differs due to the fact that data is being called from a local JSON file as apposed to being fetched via an API.

The UI is contained within the file src/pages/StudentTasks/StudentTasks.tsx

Data is imported from the JSON file in the following as follows:

import testData from './assignments.json';
Therefore the table data is defined as follows:

const tableData = useMemo(() => testData.assignments, []);

However when actually importing from the backend the following import will likely be used:

// Removed useAPI import as it's currently not needed for JSON data. Uncomment when fetching data from an API.
import useAPI from "hooks/useAPI";

This should be the API call to the backend to retrieve the student tasks from the DB.

// Commented out useEffect for fetching student tasks from an API. Uncomment when needed.
  /*
  useEffect(() => {
    fetchStudentTasks({ url: '/assignments' }); // Verify this is the correct endpoint
  }, [fetchStudentTasks]);
  */

Main Table

UI changes

Previous UI:

Current UI:

Changes

  • Create new student assignments / tasks table utilizing TypeScript to implement main features and functionalities prior version.
  • Added a search box at the top for searching any input related to assignments.
  • Added a dropdown for every column to filter assignments accordingly.
  • Added a page navigation feature under the table.

Code Changes

New TypeScript Student Tasks Table

There are three main files associated with the rendering of this table and the Student Tasks UI as a whole:

1) src/pages/StudentTasks/StudentTasks.tsx

  Renders the UI and contains the logic for the table.

2) src/pages/StudentTasks/StudentTaskColumns.tsx

  Defines the table's columns.

3) src/components/Table/Table.tsx

  Defines the base logic for the table implementation.
Dropdown Feature & Developer Implications + UI Guidence

We edited the class src/components/Table/Table.tsx to have a accommodate three different options for searching the columns: a dropdown, a search box (input) or neither.

in Interface TableProps see:


// Table.tsx

interface TableProps {
  // other properties...

  // new property for search control
  columnSearchMode?: 'none' | 'input' | 'dropdown';
  dropdownOptions?: Record<string, string[]>; // if 'dropdown', provide options for each column
}

We defined the default column search property to be a search box (input) as seen below:


// Table.tsx

const Table: React.FC<TableProps> = ({
  // other properties...
  columnSearchMode = 'input' // default when creating a Table 
  
})

As a feature of our implementation and design, the developer has options for choosing which columnSearchMode to implement:

Currently, columnSearchMode is parameterized with the dropdown option as seen in UI of table above.

Therefore when rendering the table in StudentTasks.tsx, columnSearchMode can be parametrized with 3 different options based on the developer's choosing.


// StudentTasks.tsx

 <Table
            data={tableData}
            columns={tableColumns}
            columnSearchMode={'dropdown'} // Can be 'none', 'input', or 'dropdown'
            dropdownOptions={dropdownOptions}
            headerCellStyle={{background: "#f2f2f2"}}
            // ... other props
          />

Parameterizing columnSearchMode with 'none' or 'input' is as simple as entering said parameter name, nothing else is required and the UI should render.

However, for 'dropdown', the dropdownOptions prop needs to be included to pull data for the dropdown.

Side Table

UI changes

Previous UI:

Current UI:

Changes

  • Transfer all the code from Ruby on Rails views to React and TypeScript.
  • Delete the line between Course Name and the start of team member list
  • Add the line between the end of team member list and Course Name

Code changes

This task was implemented mainly in two files: StudentTasks.css and StudentTasksBox.tsx

  • StudentTasks.css

This file contains the majority of the styles of this box.

  • StudentTasksBox.tsx

First, defined interface for the table data and pass these data as parameters

interface StudentTasksBoxParameter {
  duties: Duty[];
  revisions: Revision[];
  studentsTeamedWith: StudentsTeamedWith;
}

We also need to define a function to calculate days left with the the current time and due time

  const calculateDaysLeft = (dueDate: string) => {
    const today = new Date();
    const date = new Date(dueDate);
    const differenceInTime = date.getTime() - today.getTime();
    const differenceInDays = Math.ceil(differenceInTime / (1000 * 3600 * 24));
    return differenceInDays > 0 ? differenceInDays : 0;
  };

Next, we need to filter out those assignments that have not yet reached their due date.

const tasksNotStarted = duties.filter(duty => (calculateDaysLeft(duty.dueDate) > 0))

Finally, we can display the data as intended template

Task not yet start

<strong>
          <span className="tasknum"> {tasksNotStarted.length} </span> Tasks not yet started<br />
      </strong>
      <br />
      {tasksNotStarted.map(task => {
        const daysLeft = calculateDaysLeft(task.dueDate);
        const dayText = daysLeft > 1 ? 'days' : 'day';
        return (
          <div>
            <span>   » {task.name} ({daysLeft} {dayText} left)</span>
          </div>
        )
      })}


Student who have teamed with you

<strong>
        Students who have teamed with you<br />
      </strong>
      <br />

      {
        Object.entries(studentsTeamedWith).map(([semester, students]) => (
          <div>
            <strong>  <span className="tasknum"> 
              {students.length} </span>
                {semester}
              </strong><br />
            {students.map((student => (
              <div>
                <span className="notification">  » {student} </span>
              </div>
            )))}
            <br/>
          </div>
        ))
      }

Lazy Loading

Current View

Implementation

Prerequisites

React.js Typescript

Fork from this repo:
https://github.com/ychen-207523/reimplementation-front-end
https://github.com/expertiza/reimplementation-back-end

Please follow the video instructions for the setup of the project given in the README in the backend repository.

Connecting Reimplementation Frontend and Reimplementation Back end

After setting up remote interpreter, run below commands in bash:

bundle install

rake db:create

rake db:migrate

rails s -p 4000 -b '0.0.0.0'

Now run below commands in terminal for backend:

mysql -u dev -pexpertiza

use reimplementation_development;

After this run insert commands:

INSERT INTO institutions (name, created_at, updated_at) VALUES ('North Carolina State University', NOW(), NOW())

Now open a terminal, run below cmd:

rails console

BCrypt::Password.create('password123')

Copy output of above cmd in some file.

Run below command in backend:

INSERT INTO users (name, email, password_digest, role_id, created_at, updated_at, full_name, institution_id) VALUES ('admin', 'admin2@example.com', '$2a$12$TWct/jRMKbb1Pm1NtxKmPuAkk8IOIHnJyBaU4eiMQ5MjV41Se0AXG', 1, NOW(), NOW(), 'admin admin', 1);

To run React.js (Frontend) from VS Code:

In the project directory, you can run:

npm start

Runs the app in the development mode.

npm test

Launches the test runner in the interactive watch mode.

npm run build

Builds the app for production to the build folder.

Open http://localhost:3000 to view it in the browser.

Login details: admin (password123)

In case it doesn’t work: Try deleting the rsa_keys.yml file in ruby mine and try login again.

Future Scope

As mentioned in the CHANGES section, we used test data for our tables. The data is called from a JSON file in the same folder as our Student Task UI src/pages/StudentTasks/assignments.json.

In order to call data from the SQL server running on the backend, we need to retrieve it using API endpoints. Some of tables may need added or deleted columns to appropriately coincide with the current table column structure.

Moreover, some of the imports and API calls are already coded into src/pages/StudentTasks/StudentTasks.tsx but not complete as it was not necessary for merely changing the front end portion of the project.

useAPI import commented out:


// StudentTasks.tsx

// Removed useAPI import as it's currently not needed for JSON data. Uncomment when fetching data from an API.
// import useAPI from "hooks/useAPI"


We will likely need to create a constant that coincides with an API call to the assignments table, and make sure that table has all the necessary columns.



// StudentTasks.tsx


const StudentTasks = () => {
  // These hooks can be uncommented and used when integrating API calls
  // const { error, isLoading, data: studentTasks, sendRequest: fetchStudentTasks } = useAPI();
  // const { data: coursesResponse, sendRequest: fetchCourses } = useAPI();

  const duties = testData.duties;
  const taskRevisions = testData.revisions;
  const studentsTeamedWith = testData.studentsTeamedWith;

  // Commented out useEffect for fetching student tasks from an API. Uncomment when needed.
  /*
  useEffect(() => {
    fetchStudentTasks({ url: '/assignments' }); // Verify this is the correct endpoint
  }, [fetchStudentTasks]);
  */


Making sure the data being called is from the SQL server is likely more complicated since it is an API call vs a direct call to a local file. The constant tableData will likely need to bel altered.


// StudentTasks.tsx



// Memoize the table data to use assignments from testData
  const tableData = useMemo(() => testData.assignments, []);


Finally when calling data from the SQL server, we’ll likely need to handle errors of the API calls.


// StudentTasks.tsx

// Render the component with the Table component and necessary controls
  return (
    <div className="student-tasks">
      <Container fluid className="px-md-4">
        {/* Uncomment and adjust error handling when integrating with API calls
        {error && <div className="alert alert-danger" role="alert">{error}</div>}
        */}
        <Row className="mb-2">
          <Col>
            <h2>Assignments</h2>
          </Col>
        </Row>
// ...rest of table rendering

Team