Skip to content

Commit

Permalink
Merge pull request #486 from timeoff-management/tom-xxx-grouped-team-…
Browse files Browse the repository at this point in the history
…view

Introduce Grouped mode to the Team View
  • Loading branch information
vpp authored Aug 10, 2021
2 parents 3fdbe6f + d70267d commit 75f19b1
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 56 deletions.
3 changes: 2 additions & 1 deletion lib/model/db/department.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ module.exports = function(sequelize, DataTypes) {
// Return users related to current department and still active
promise_active_users : function(){
return this.getUsers({
where : sequelize.models.User.get_active_user_filter()
scope: ["withDepartments"],
where: sequelize.models.User.get_active_user_filter()
});
},

Expand Down
113 changes: 68 additions & 45 deletions lib/route/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var express = require('express'),
const {createNewLeave, getLeaveForUserView, doesUserHasExtendedViewOfLeave} = require('../model/leave');
const { leaveIntoObject } = require('../model/Report');
const { getCommentsForLeave } = require('../model/comment');
const { sorter } = require('../util');

router.post('/bookleave/', function(req, res){

Expand Down Expand Up @@ -125,66 +126,88 @@ router.get('/', function(req, res) {

});

router.get('/teamview/', function(req, res){
router.get('/teamview/', async (req, res) => {
const user = req.user;

if (req.user.company.is_team_view_hidden && ! req.user.admin) {
if (user.company.is_team_view_hidden && !user.admin) {
return res.redirect_with_session('/');
}

const base_date = validator.isDate(req.query['date'])
? moment.utc(req.query['date'])
: req.user.company.get_today();
: user.company.get_today();

const team_view = new TeamView({
base_date : base_date,
user : req.user,
});
const grouped_mode = !! req.query['grouped_mode'];

const team_view = new TeamView({ user, base_date });

const current_deparment_id = validator.isNumeric(req.query['department'])
const currentDepartmentId = validator.isNumeric(req.query['department'])
? req.query['department']
: null;

Promise.join(
team_view.promise_team_view_details({
department_id : current_deparment_id,
}),
req.user.get_company_with_all_leave_types(),
(team_view_details, company) => {
// Enrich "team view details" with statistics as how many deducted days each employee spent current month
team_view
.inject_statistics({
team_view_details : team_view_details,
leave_types : company.leave_types,
})
.then( team_view_details => team_view.restrainStatisticsForUser({
team_view_details : team_view_details,
user : req.user,
}))
.then(team_view_details => res.render('team_view', {
base_date : base_date,
prev_date : moment.utc(base_date).add(-1,'month'),
next_date : moment.utc(base_date).add(1,'month'),
users_and_leaves : team_view_details.users_and_leaves,
related_departments : team_view_details.related_departments,
current_department : team_view_details.current_department,
company : company,
})
);
})
.catch(error => {
console.error(
'An error occured when user '+req.user.id+
' tried to access Teamview page: '+error
);
req.session.flash_error('Failed to access Teamview page. Please contact administrator.');
if (error.hasOwnProperty('user_message')) {
req.session.flash_error(error.user_message);
}
return res.redirect_with_session('/');
try {
const [team_view_details, company] = await Promise.all([
team_view.promise_team_view_details({
department_id: currentDepartmentId,
}),
user.get_company_with_all_leave_types(),
]);

// Enrich "team view details" with statistics as how many deducted days each employee spent current month
const team_view_details_with_stat = await team_view.inject_statistics({
team_view_details,
leave_types: company.leave_types,
});

const {users_and_leaves, related_departments, current_department} = await team_view.restrainStatisticsForUser({
user,
team_view_details: team_view_details_with_stat,
});

const renderingContext = {
company,
users_and_leaves,
related_departments,
current_department,
base_date,
prev_date: moment.utc(base_date).add(-1, 'month'),
next_date: moment.utc(base_date).add(1, 'month'),
};

if (grouped_mode) {
renderingContext.grouped_mode = true;
renderingContext.users_and_leaves_by_departments = groupUsersOnTeamViewByDepartments(users_and_leaves);
}

res.render('team_view', renderingContext);
}
catch (error) {
console.error(
`An error occurred when user ${user.id} tried to access TeamView page: ${error}, at ${error.stack}`
);
req.session.flash_error('Failed to access TeamView page. Please contact administrator.');

if (error.hasOwnProperty('user_message')) {
req.session.flash_error(error.user_message);
}

return res.redirect_with_session('/');
};
});

const groupUsersOnTeamViewByDepartments = (usersAndLeaves) => {
const departmentsDict = usersAndLeaves.reduce(
(acc, item) => ({ ...acc, [item.user.department.id]: { departmentName: item.user.department.name, users_and_leaves: [] } }),
{}
);

usersAndLeaves.forEach(item => {
departmentsDict[item.user.department.id].users_and_leaves.push(item);
});

return Object.values(departmentsDict).sort((a, b) => sorter(a.departmentName, b.departmentName));
};

router.get('/feeds/', function(req, res){
req.user
.getFeeds()
Expand Down
2 changes: 1 addition & 1 deletion views/partials/footer.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<footer class="footer custom-footer">
<p>
<span class="pull-left">© <a href="http://timeoff.management">TimeOff.management</a> 2014-2019</span>
<span class="pull-left">© <a href="http://timeoff.management">TimeOff.management</a> 2014-2021</span>
<span class="pull-right">
<a href="https://github.com/timeoff-management/application"><i class="fa fa-github fa-lg"></i></a>
<a href="https://twitter.com/FreeTimeOffApp"><i class="fa fa-twitter fa-lg"></i></a>
Expand Down
2 changes: 1 addition & 1 deletion views/partials/team_view_url_parameters.hbs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{{# if current_department }}department={{current_department.id}}{{/if}}{{# if base_date }}&date={{ as_date_formatted base_date 'YYYY-MM' }}{{/if}}
{{#if current_department }}department={{current_department.id}}{{/if}}{{#if base_date }}&date={{ as_date_formatted base_date 'YYYY-MM' }}{{/if}}{{#if grouped_mode}}&grouped_mode={{grouped_mode}}{{/if}}
81 changes: 73 additions & 8 deletions views/team_view.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
<h1>Team View</h1>

<div class="row">
<div class="col-md-6 lead">{{logged_user.name}} {{logged_user.lastname}}'s team <a href="/calendar/feeds/" data-toggle="tooltip" data-placement="right" title="Export Team View to external calendars"><span class="fa fa-rss"></span></a></div>
<div class="col-md-6 lead">{{logged_user.name}} {{logged_user.lastname}}'s team <a href="/calendar/feeds/" data-toggle="tooltip" data-placement="right" title="Export Team View to external calendars"><span class="fa fa-rss"></span></a></div>
<div class="col-md-3 col-md-offset-3">
<div class="btn-group btn-group-sm pull-right" role="group">
<a href="/calendar/teamview/?{{> team_view_url_parameters grouped_mode = 0 }}" class="btn btn-default" {{#unless grouped_mode}}disabled=disabled{{/unless}}>All</a>
<a href="/calendar/teamview/?{{> team_view_url_parameters grouped_mode = 1 }}" class="btn btn-default" {{#if grouped_mode}}disabled=disabled{{/if}}>By Department</a>
</div>
</div>
</div>

{{> show_flash_messages }}
Expand All @@ -29,16 +35,73 @@

<div class="row">&nbsp;</div>

{{#if grouped_mode}}

{{#each users_and_leaves_by_departments}}

{{#if @index}}
<div class="row">
<div class="col-md-12">&nbsp;</div>
</div>
{{/if}}

<div class="row clearfix">
<div class="col-md-12">
<table class="team-view-table table-hover">
<thead>
<tr>
<td class="team-view-header" colspan="2">
<div class="pull-left">
<h3>{{this.departmentName}}</h3>
</div>
</td>

{{#each this.users_and_leaves.0.days }}
<td colspan="2" class="team-view-header"><b>{{as_date_formatted this.moment 'dd'}}</b></td>
{{/each}}
</tr>
</thead>

<tbody>
{{#each this.users_and_leaves}}
<tr class="teamview-user-list-row" data-vpp-user-list-row={{this.user.id}}>
<td class="left-column-cell cross-link user-details-summary-trigger" data-user-id={{this.user.id}}>{{#if ../../logged_user.admin}} {{#with this.user }}<a href="/users/edit/{{this.id}}/">{{ this.full_name }}</a>{{/with}}{{else}}{{#with this.user }}<span>{{ this.full_name }}</span>{{/with}}{{/if}}</td>
<td>
<span class="teamview-deducted-days"
{{#if statistics }}
data-content="In {{as_date_formatted ../../base_date 'MMMM, YYYY' }} {{#with this.user }}{{this.full_name}} used {{../../statistics.deducted_days }} days from allowance{{/with}}"
data-placement="right"
data-toggle="popover"
data-trigger="focus hover"
{{/if}}
>
{{#if statistics }}{{ statistics.deducted_days }}{{/if}}
</span>
</td>
{{#each this.days}}
{{> calendar_cell day = this}}
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>

{{/each}}

{{else}}


<div class="row clearfix">
<div class="col-md-12">
<table class="team-view-table table-hover">
<thead>
<tr>
<td class="team-view-header" colspan="2">
<div class="dropdown pull-left">
<button class="btn btn-default dropdown-toggle left-column-cell" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
{{# if current_department }}{{current_department.name}}{{else}}All departments{{/if}}
{{#if current_department }}{{current_department.name}}{{else}}All departments{{/if}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
Expand All @@ -51,29 +114,29 @@
</div>
</td>

{{# each users_and_leaves.0.days }}
{{#each users_and_leaves.0.days }}
<td colspan="2" class="team-view-header"><b>{{as_date_formatted this.moment 'dd'}}</b></td>
{{/each}}
</tr>
</thead>

<tbody>
{{# each users_and_leaves}}
{{#each users_and_leaves}}
<tr class="teamview-user-list-row" data-vpp-user-list-row={{this.user.id}}>
<td class="left-column-cell cross-link user-details-summary-trigger" data-user-id={{this.user.id}}>{{# if ../logged_user.admin}} {{#with this.user }}<a href="/users/edit/{{this.id}}/">{{ this.full_name }}</a>{{/with}} {{else}}{{#with this.user }}<span>{{ this.full_name }}</span>{{/with}}{{/if}}</td>
<td class="left-column-cell cross-link user-details-summary-trigger" data-user-id={{this.user.id}}>{{#if ../logged_user.admin}} {{#with this.user }}<a href="/users/edit/{{this.id}}/">{{ this.full_name }}</a>{{/with}}{{else}}{{#with this.user }}<span>{{ this.full_name }}</span>{{/with}}{{/if}}</td>
<td>
<span class="teamview-deducted-days"
{{# if statistics }}
{{#if statistics }}
data-content="In {{as_date_formatted ../base_date 'MMMM, YYYY' }} {{# with this.user }}{{this.full_name}} used {{../statistics.deducted_days }} days from allowance{{/with}}"
data-placement="right"
data-toggle="popover"
data-trigger="focus hover"
{{/if}}
>
{{# if statistics }}{{ statistics.deducted_days }}{{/if}}
{{#if statistics }}{{ statistics.deducted_days }}{{/if}}
</span>
</td>
{{# each this.days}}
{{#each this.days}}
{{> calendar_cell day = this}}
{{/each}}
</tr>
Expand All @@ -83,6 +146,8 @@
</div>
</div>

{{/if}}

<div class="row clearfix">&nbsp;</div>

{{> footer }}

0 comments on commit 75f19b1

Please sign in to comment.