Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor projects page #211

Merged
merged 16 commits into from
Mar 28, 2022
Merged

Refactor projects page #211

merged 16 commits into from
Mar 28, 2022

Conversation

shalapatil
Copy link
Contributor

@shalapatil shalapatil commented Mar 17, 2022

Notion card

Summary

Refactored projects index page to use react instead of erb file. This is very basic page. All the required components of the page are not added. Someone from FE needs to work on it.

Preview

Expected view
Screenshot 2022-03-17 at 11 13 39 AM

Current implemented view
Screenshot 2022-03-17 at 11 19 19 AM

Clicking on any project, takes to this page
Screenshot 2022-03-21 at 5 39 31 PM

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to
    not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Checklist:

  • I have manually tested all workflows
  • I have performed a self-review of my own code
  • I have added automated tests for my code

@vipulnsward vipulnsward temporarily deployed to miru-review-pr-211 March 17, 2022 05:52 Inactive

const fetchProjects = async () => {
const res = await projects.get();
if (res.status == 200) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use then and catch instead of checking the status.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need this condition. Because anyway these statuses are handled in the registerIntercepts. You can enclose the whole code in a try..catch block.

</div>
</div>
{/* {showEditDialog ? (
<EditProject
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why commented code? please remove.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will uncomment it when I add related modals


const fetchProjects = async () => {
const res = await projects.get();
if (res.status == 200) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need this condition. Because anyway these statuses are handled in the registerIntercepts. You can enclose the whole code in a try..catch block.

@@ -0,0 +1,81 @@
import * as React from "react";
import { minutesToHHMM } from "../../helpers/hhmm-parser";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { minutesToHHMM } from "../../helpers/hhmm-parser";
import { minutesToHHMM } from "helpers/hhmm-parser";

Comment on lines 10 to 18
def projects
projects = current_user.current_workspace.projects
projects.kept.map { | project |
{ id: project.id,
name: project.name,
clientName: project.client.name,
isBillable: project.billable,
minutesSpent: project.total_hours_logged } }
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this method to private. Also try to memoize

Comment on lines 44 to 61
def total_hours_logged(time_frame = "week")
from, to = week_month_year(time_frame)
timesheet_entries.where(work_date: from..to).sum(:duration)
end

# Move weeK_month_year method copied from client.rb to common place
def week_month_year(time_frame)
case time_frame
when "last_week"
return ((Date.today.beginning_of_week) - 7), ((Date.today.end_of_week) - 7)
when "month"
return Date.today.beginning_of_month, Date.today.end_of_month
when "year"
return Date.today.beginning_of_year, Date.today.end_of_year
else
return Date.today.beginning_of_week, Date.today.end_of_week
end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are using the same method in some other model. Can we move this to a common concern

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I have added the same in the comment. where should we move this to? like what is the place for common functionality.

Also added state to check if project is clicked for showing project details
@@ -4,8 +4,7 @@ class ProjectsController < ApplicationController
skip_after_action :verify_authorized

def index
@query = Project.ransack(params[:q])
@projects = @query.result(distinct: true)
authorize :project
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be authorize Project to denote that the policy belongs to the Project model. We should use symbols for policies when there is no associated model with them

Shows the project basic details and the project member details
@github-actions
Copy link

github-actions bot commented Mar 21, 2022

Current Code Coverage Percent of this PR:

78.53 %

Files having coverage below 100%

Impacted Files Coverage
/app/controllers/concerns/error_handler.rb 69.44 %
/app/controllers/projects_controller.rb 46.15 %
/app/controllers/concerns/timesheet.rb 75.0 %
/app/controllers/invoices_controller.rb 66.67 %
/app/controllers/workspaces_controller.rb 77.78 %
/app/controllers/clients_controller.rb 94.44 %
/app/models/company.rb 90.48 %
/app/models/timesheet_entry.rb 76.92 %
/app/models/project.rb 89.66 %
/app/policies/timesheet_entry_policy.rb 50.0 %
/app/policies/project_policy.rb 85.71 %
/app/policies/client_policy.rb 80.0 %
/app/controllers/users/passwords_controller.rb 41.67 %
/app/controllers/users/omniauth_callbacks_controller.rb 25.0 %
/app/controllers/users/sessions_controller.rb 25.0 %
/app/controllers/users/registrations_controller.rb 40.0 %
/app/controllers/internal_api/v1/projects_controller.rb 75.0 %
/app/controllers/internal_api/v1/reports_controller.rb 88.89 %
/app/controllers/internal_api/v1/timesheet_entry_controller.rb 40.0 %
/app/controllers/internal_api/v1/workspaces_controller.rb 85.71 %
/app/controllers/internal_api/v1/clients_controller.rb 80.77 %
/lib/authentication/google.rb 0.0 %

@ajinkyaa
Copy link
Contributor

@shalapatil Please remove commented code.

Copy link
Member

@akhilgkrishnan akhilgkrishnan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some suggestions and changes

app/controllers/internal_api/v1/projects_controller.rb Outdated Show resolved Hide resolved
app/javascript/src/components/Projects/index.tsx Outdated Show resolved Hide resolved

const show = async id => axios.get(`${path}/${id}`);

const projects = { get, show };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const projects = { get, show };
const projectApi = { get, show };

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for all the API's we can use these pattern


const projects = { get, show };

export default projects;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export default projects;
export default projectApi;

Comment on lines 13 to 19
const fetchProjects = () => {

projects.get()
.then(res => setAllProjects(res.data.projects))
.catch(err => console.log(err));

};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const fetchProjects = () => {
projects.get()
.then(res => setAllProjects(res.data.projects))
.catch(err => console.log(err));
};
const fetchProjects = async () => {
try {
const response = await projects.get();
setProjects(response.data.projects);
} catch(err => console.log(err));
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the difference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

import ProjectList from "./projectList";

const Projects = ({ editIcon, deleteIcon, isAdminUser }) => {
const [allProjects, setAllProjects] = React.useState([]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const [allProjects, setAllProjects] = React.useState([]);
const [projects, setProjects] = React.useState<ProjectsData[]>([]);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can call the state as Projects.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, add an interface for ProjectsData

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines 11 to 15
const fetchProject = () => {
projectsAPI.show(id)
.then(res => setProject(res.data.project))
.catch (err => {console.log(err);});
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use async await method. refer the above comment

import { setAuthHeaders, registerIntercepts } from "apis/axios";
import projectsAPI from "apis/projects";
import { Member } from "./member";
import { minutesToHHMM } from "../../helpers/hhmm-parser";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove unused variables

@@ -0,0 +1,90 @@
import * as React from "react";
import { setAuthHeaders, registerIntercepts } from "apis/axios";
import projectsAPI from "apis/projects";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import projectsAPI from "apis/projects";
import projectAPI from "apis/projects";

}, []);

return (

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove unwanted spacing

app/controllers/internal_api/v1/projects_controller.rb Outdated Show resolved Hide resolved
app/controllers/internal_api/v1/projects_controller.rb Outdated Show resolved Hide resolved
app/controllers/internal_api/v1/projects_controller.rb Outdated Show resolved Hide resolved
app/controllers/internal_api/v1/projects_controller.rb Outdated Show resolved Hide resolved
app/controllers/internal_api/v1/projects_controller.rb Outdated Show resolved Hide resolved
Comment on lines 19 to 24
projects.kept.map { | project |
{ id: project.id,
name: project.name,
clientName: project.client.name,
isBillable: project.billable,
minutesSpent: project.total_hours_logged } }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part should be moved to the individual controller action, so that def projects is intended to do only one thing and is reusable. Not a blocking change though.

@vipulnsward vipulnsward temporarily deployed to miru-review-pr-211 March 25, 2022 08:58 Inactive
@@ -3,7 +3,10 @@
json.project_details do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add the following just above this line to auto convert the keys in response to camelCase

json.key_format! camelize: :lower
json.deep_format_keys!

You won't need to modify the keys on FE side after this. For example, no need to change isBillable to is_billable in React code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, don't have any of the you specified requirement atm. Will add it whenver required.

@vipulnsward vipulnsward temporarily deployed to miru-review-pr-211 March 28, 2022 08:29 Inactive
end
json.isBillable project.billable
json.minutesSpent project.total_hours_logged
end
Copy link
Contributor

@apoorv-mishra apoorv-mishra Mar 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you try

json.key_format! camelize: :lower
json.deep_format_keys!
json.projects do
  json.array! projects do |project|
    json.id project.id
    json.name project.name
    json.client do
      json.name project.client.name
    end
    json.is_billable project.billable
    json.minutes_spent project.total_hours_logged
  end
end

?

@vipulnsward vipulnsward temporarily deployed to miru-review-pr-211 March 28, 2022 09:36 Inactive
Copy link
Member

@akhilgkrishnan akhilgkrishnan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Comment on lines 29 to 39
project_members = project.project_member_details.map { | member |
{ name: member[:name],
hourlyRate: member[:hourly_rate],
minutesSpent: member[:minutes_spent],
cost: member[:hourly_rate] * member[:minutes_spent] / 60 }}
{ id: project.id,
name: project.name,
clientName: project.client.name,
isBillable: project.billable,
minutesSpent: project.total_hours_logged,
projectMembers: project_members }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this is not updated?

@vipulnsward vipulnsward temporarily deployed to miru-review-pr-211 March 28, 2022 09:59 Inactive
@vipulnsward vipulnsward temporarily deployed to miru-review-pr-211 March 28, 2022 11:33 Inactive
Copy link
Contributor

@ajinkyaa ajinkyaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is incomplete UI for project list and project details page.
which we will pick up in next PR

@shalapatil shalapatil merged commit c7a3242 into develop Mar 28, 2022
@akhilgkrishnan akhilgkrishnan deleted the refactor-projects-page branch April 5, 2022 04:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants