Skip to content

Commit 75f19b1

Browse files
authored
Merge pull request #486 from timeoff-management/tom-xxx-grouped-team-view
Introduce Grouped mode to the Team View
2 parents 3fdbe6f + d70267d commit 75f19b1

File tree

5 files changed

+145
-56
lines changed

5 files changed

+145
-56
lines changed

lib/model/db/department.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ module.exports = function(sequelize, DataTypes) {
9898
// Return users related to current department and still active
9999
promise_active_users : function(){
100100
return this.getUsers({
101-
where : sequelize.models.User.get_active_user_filter()
101+
scope: ["withDepartments"],
102+
where: sequelize.models.User.get_active_user_filter()
102103
});
103104
},
104105

lib/route/calendar.js

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var express = require('express'),
1414
const {createNewLeave, getLeaveForUserView, doesUserHasExtendedViewOfLeave} = require('../model/leave');
1515
const { leaveIntoObject } = require('../model/Report');
1616
const { getCommentsForLeave } = require('../model/comment');
17+
const { sorter } = require('../util');
1718

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

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

126127
});
127128

128-
router.get('/teamview/', function(req, res){
129+
router.get('/teamview/', async (req, res) => {
130+
const user = req.user;
129131

130-
if (req.user.company.is_team_view_hidden && ! req.user.admin) {
132+
if (user.company.is_team_view_hidden && !user.admin) {
131133
return res.redirect_with_session('/');
132134
}
133135

134136
const base_date = validator.isDate(req.query['date'])
135137
? moment.utc(req.query['date'])
136-
: req.user.company.get_today();
138+
: user.company.get_today();
137139

138-
const team_view = new TeamView({
139-
base_date : base_date,
140-
user : req.user,
141-
});
140+
const grouped_mode = !! req.query['grouped_mode'];
141+
142+
const team_view = new TeamView({ user, base_date });
142143

143-
const current_deparment_id = validator.isNumeric(req.query['department'])
144+
const currentDepartmentId = validator.isNumeric(req.query['department'])
144145
? req.query['department']
145146
: null;
146147

147-
Promise.join(
148-
team_view.promise_team_view_details({
149-
department_id : current_deparment_id,
150-
}),
151-
req.user.get_company_with_all_leave_types(),
152-
(team_view_details, company) => {
153-
// Enrich "team view details" with statistics as how many deducted days each employee spent current month
154-
team_view
155-
.inject_statistics({
156-
team_view_details : team_view_details,
157-
leave_types : company.leave_types,
158-
})
159-
.then( team_view_details => team_view.restrainStatisticsForUser({
160-
team_view_details : team_view_details,
161-
user : req.user,
162-
}))
163-
.then(team_view_details => res.render('team_view', {
164-
base_date : base_date,
165-
prev_date : moment.utc(base_date).add(-1,'month'),
166-
next_date : moment.utc(base_date).add(1,'month'),
167-
users_and_leaves : team_view_details.users_and_leaves,
168-
related_departments : team_view_details.related_departments,
169-
current_department : team_view_details.current_department,
170-
company : company,
171-
})
172-
);
173-
})
174-
.catch(error => {
175-
console.error(
176-
'An error occured when user '+req.user.id+
177-
' tried to access Teamview page: '+error
178-
);
179-
req.session.flash_error('Failed to access Teamview page. Please contact administrator.');
180-
if (error.hasOwnProperty('user_message')) {
181-
req.session.flash_error(error.user_message);
182-
}
183-
return res.redirect_with_session('/');
148+
try {
149+
const [team_view_details, company] = await Promise.all([
150+
team_view.promise_team_view_details({
151+
department_id: currentDepartmentId,
152+
}),
153+
user.get_company_with_all_leave_types(),
154+
]);
155+
156+
// Enrich "team view details" with statistics as how many deducted days each employee spent current month
157+
const team_view_details_with_stat = await team_view.inject_statistics({
158+
team_view_details,
159+
leave_types: company.leave_types,
160+
});
161+
162+
const {users_and_leaves, related_departments, current_department} = await team_view.restrainStatisticsForUser({
163+
user,
164+
team_view_details: team_view_details_with_stat,
184165
});
185166

167+
const renderingContext = {
168+
company,
169+
users_and_leaves,
170+
related_departments,
171+
current_department,
172+
base_date,
173+
prev_date: moment.utc(base_date).add(-1, 'month'),
174+
next_date: moment.utc(base_date).add(1, 'month'),
175+
};
176+
177+
if (grouped_mode) {
178+
renderingContext.grouped_mode = true;
179+
renderingContext.users_and_leaves_by_departments = groupUsersOnTeamViewByDepartments(users_and_leaves);
180+
}
181+
182+
res.render('team_view', renderingContext);
183+
}
184+
catch (error) {
185+
console.error(
186+
`An error occurred when user ${user.id} tried to access TeamView page: ${error}, at ${error.stack}`
187+
);
188+
req.session.flash_error('Failed to access TeamView page. Please contact administrator.');
189+
190+
if (error.hasOwnProperty('user_message')) {
191+
req.session.flash_error(error.user_message);
192+
}
193+
194+
return res.redirect_with_session('/');
195+
};
186196
});
187197

198+
const groupUsersOnTeamViewByDepartments = (usersAndLeaves) => {
199+
const departmentsDict = usersAndLeaves.reduce(
200+
(acc, item) => ({ ...acc, [item.user.department.id]: { departmentName: item.user.department.name, users_and_leaves: [] } }),
201+
{}
202+
);
203+
204+
usersAndLeaves.forEach(item => {
205+
departmentsDict[item.user.department.id].users_and_leaves.push(item);
206+
});
207+
208+
return Object.values(departmentsDict).sort((a, b) => sorter(a.departmentName, b.departmentName));
209+
};
210+
188211
router.get('/feeds/', function(req, res){
189212
req.user
190213
.getFeeds()

views/partials/footer.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<footer class="footer custom-footer">
88
<p>
9-
<span class="pull-left">© <a href="http://timeoff.management">TimeOff.management</a> 2014-2019</span>
9+
<span class="pull-left">© <a href="http://timeoff.management">TimeOff.management</a> 2014-2021</span>
1010
<span class="pull-right">
1111
<a href="https://github.com/timeoff-management/application"><i class="fa fa-github fa-lg"></i></a>
1212
<a href="https://twitter.com/FreeTimeOffApp"><i class="fa fa-twitter fa-lg"></i></a>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{# if current_department }}department={{current_department.id}}{{/if}}{{# if base_date }}&date={{ as_date_formatted base_date 'YYYY-MM' }}{{/if}}
1+
{{#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}}

views/team_view.hbs

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44
<h1>Team View</h1>
55

66
<div class="row">
7-
<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>
7+
<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>
8+
<div class="col-md-3 col-md-offset-3">
9+
<div class="btn-group btn-group-sm pull-right" role="group">
10+
<a href="/calendar/teamview/?{{> team_view_url_parameters grouped_mode = 0 }}" class="btn btn-default" {{#unless grouped_mode}}disabled=disabled{{/unless}}>All</a>
11+
<a href="/calendar/teamview/?{{> team_view_url_parameters grouped_mode = 1 }}" class="btn btn-default" {{#if grouped_mode}}disabled=disabled{{/if}}>By Department</a>
12+
</div>
13+
</div>
814
</div>
915

1016
{{> show_flash_messages }}
@@ -29,16 +35,73 @@
2935

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

38+
{{#if grouped_mode}}
39+
40+
{{#each users_and_leaves_by_departments}}
41+
42+
{{#if @index}}
43+
<div class="row">
44+
<div class="col-md-12">&nbsp;</div>
45+
</div>
46+
{{/if}}
47+
3248
<div class="row clearfix">
3349
<div class="col-md-12">
3450
<table class="team-view-table table-hover">
51+
<thead>
52+
<tr>
53+
<td class="team-view-header" colspan="2">
54+
<div class="pull-left">
55+
<h3>{{this.departmentName}}</h3>
56+
</div>
57+
</td>
58+
59+
{{#each this.users_and_leaves.0.days }}
60+
<td colspan="2" class="team-view-header"><b>{{as_date_formatted this.moment 'dd'}}</b></td>
61+
{{/each}}
62+
</tr>
63+
</thead>
64+
65+
<tbody>
66+
{{#each this.users_and_leaves}}
67+
<tr class="teamview-user-list-row" data-vpp-user-list-row={{this.user.id}}>
68+
<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>
69+
<td>
70+
<span class="teamview-deducted-days"
71+
{{#if statistics }}
72+
data-content="In {{as_date_formatted ../../base_date 'MMMM, YYYY' }} {{#with this.user }}{{this.full_name}} used {{../../statistics.deducted_days }} days from allowance{{/with}}"
73+
data-placement="right"
74+
data-toggle="popover"
75+
data-trigger="focus hover"
76+
{{/if}}
77+
>
78+
{{#if statistics }}{{ statistics.deducted_days }}{{/if}}
79+
</span>
80+
</td>
81+
{{#each this.days}}
82+
{{> calendar_cell day = this}}
83+
{{/each}}
84+
</tr>
85+
{{/each}}
86+
</tbody>
87+
</table>
88+
</div>
89+
</div>
90+
91+
{{/each}}
92+
93+
{{else}}
3594

95+
96+
<div class="row clearfix">
97+
<div class="col-md-12">
98+
<table class="team-view-table table-hover">
3699
<thead>
37100
<tr>
38101
<td class="team-view-header" colspan="2">
39102
<div class="dropdown pull-left">
40103
<button class="btn btn-default dropdown-toggle left-column-cell" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
41-
{{# if current_department }}{{current_department.name}}{{else}}All departments{{/if}}
104+
{{#if current_department }}{{current_department.name}}{{else}}All departments{{/if}}
42105
<span class="caret"></span>
43106
</button>
44107
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
@@ -51,29 +114,29 @@
51114
</div>
52115
</td>
53116

54-
{{# each users_and_leaves.0.days }}
117+
{{#each users_and_leaves.0.days }}
55118
<td colspan="2" class="team-view-header"><b>{{as_date_formatted this.moment 'dd'}}</b></td>
56119
{{/each}}
57120
</tr>
58121
</thead>
59122

60123
<tbody>
61-
{{# each users_and_leaves}}
124+
{{#each users_and_leaves}}
62125
<tr class="teamview-user-list-row" data-vpp-user-list-row={{this.user.id}}>
63-
<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>
126+
<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>
64127
<td>
65128
<span class="teamview-deducted-days"
66-
{{# if statistics }}
129+
{{#if statistics }}
67130
data-content="In {{as_date_formatted ../base_date 'MMMM, YYYY' }} {{# with this.user }}{{this.full_name}} used {{../statistics.deducted_days }} days from allowance{{/with}}"
68131
data-placement="right"
69132
data-toggle="popover"
70133
data-trigger="focus hover"
71134
{{/if}}
72135
>
73-
{{# if statistics }}{{ statistics.deducted_days }}{{/if}}
136+
{{#if statistics }}{{ statistics.deducted_days }}{{/if}}
74137
</span>
75138
</td>
76-
{{# each this.days}}
139+
{{#each this.days}}
77140
{{> calendar_cell day = this}}
78141
{{/each}}
79142
</tr>
@@ -83,6 +146,8 @@
83146
</div>
84147
</div>
85148

149+
{{/if}}
150+
86151
<div class="row clearfix">&nbsp;</div>
87152

88153
{{> footer }}

0 commit comments

Comments
 (0)