Skip to content

Commit 3fdbe6f

Browse files
authored
Merge pull request #485 from timeoff-management/tom-xxx-leave-type-sorting
Fix issues with sorting of leave types
2 parents bd98cd1 + 64d5875 commit 3fdbe6f

File tree

11 files changed

+101
-83
lines changed

11 files changed

+101
-83
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,3 @@ By default the value is `en` (English). One can override it with other locales s
146146

147147
Please report any issues or feedback to <a href="https://twitter.com/FreeTimeOffApp">twitter</a> or Email: pavlo at timeoff.management
148148

149-

lib/model/db/company.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const
77
moment_tz = require('moment-timezone'),
88
_ = require('underscore'),
99
uuidv4 = require('uuid/v4');
10+
const { sorter } = require("../../util");
1011

1112

1213
module.exports = function(sequelize, DataTypes) {
@@ -413,6 +414,14 @@ module.exports = function(sequelize, DataTypes) {
413414
return this.mode === Company.get_mode_readonly_holidays();
414415
},
415416

417+
getSortedLeaveTypes: function() {
418+
const self = this;
419+
420+
const leaveTypes = self.leave_types || [];
421+
422+
return leaveTypes.sort((a, b) => sorter(a.name, b.name));
423+
},
424+
416425
}
417426
});
418427

lib/model/mixin/user/company_aware.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ var
1414
Promise = require("bluebird"),
1515
moment = require('moment');
1616

17+
const { sorter } = require("../../../util");
18+
1719
module.exports = function(sequelize){
1820

1921
/* Fetch company object associated with current user, the company object
@@ -130,17 +132,15 @@ module.exports = function(sequelize){
130132
};
131133

132134

133-
this.get_company_with_all_leave_types = function() {
134-
return this.getCompany({
135-
include : [{
136-
model : sequelize.models.LeaveType,
137-
as : 'leave_types',
138-
}],
139-
order : [
140-
[{ model : sequelize.models.LeaveType, as : 'leave_types' }, 'sort_order', 'DESC'],
141-
[{ model : sequelize.models.LeaveType, as : 'leave_types' }, 'name']
142-
]
135+
this.get_company_with_all_leave_types = async function() {
136+
const company = await this.getCompany({
137+
scope: ['with_leave_types'],
143138
});
139+
140+
company.leave_types = company.leave_types
141+
.sort((a, b) => b.sort_order - a.sort_order || sorter(a.name, b.name));
142+
143+
return company;
144144
};
145145

146146
};

lib/route/calendar.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ router.post('/bookleave/', function(req, res){
2121
req.user.promise_users_I_can_manage(),
2222
req.user.get_company_with_all_leave_types(),
2323
Promise.try( () => get_and_validate_leave_params({req})),
24-
(users, company, valide_attributes) => {
24+
(users, company, valid_attributes) => {
2525

2626
// Make sure that indexes submitted map to existing objects
27-
var employee = users[valide_attributes.user] || req.user,
28-
leave_type = company.leave_types[valide_attributes.leave_type];
27+
const employee = users[valid_attributes.user] || req.user;
28+
const [leave_type] = company.leave_types
29+
.filter(lt => `${lt.id}` === `${valid_attributes.leave_type}`);
2930

3031
if (!employee) {
3132
req.session.flash_error('Incorrect employee');
@@ -48,7 +49,7 @@ router.post('/bookleave/', function(req, res){
4849
return createNewLeave({
4950
for_employee : employee,
5051
of_type : leave_type,
51-
with_parameters : valide_attributes,
52+
with_parameters : valid_attributes,
5253
});
5354
}
5455
)

lib/route/settings.js

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ const
2121

2222
const
2323
CompanyExporter = require('../model/company/exporter');
24+
const { sorter } = require('../util');
2425

2526
// Make sure that current user is authorized to deal with settings
2627
router.all(/.*/, require('../middleware/ensure_user_is_admin'));
2728

2829

29-
router.get('/general/', function(req, res){
30-
30+
router.get('/general/', async (req, res) => {
3131
res.locals.custom_java_script.push(
3232
'/js/settings_general.js'
3333
);
@@ -36,31 +36,21 @@ router.get('/general/', function(req, res){
3636
'/css/bootstrap-datepicker3.standalone.css'
3737
);
3838

39-
var model = req.app.get('db_model');
40-
var company;
41-
42-
req.user.getCompany({
43-
include : [
44-
{ model : model.LeaveType, as : 'leave_types' },
45-
],
46-
order : [
47-
[{model: model.LeaveType, as : 'leave_types'}, 'name' ],
48-
],
49-
})
50-
.then(function(c){
51-
company = c;
52-
return company.promise_schedule();
53-
})
54-
.then(function(schedule){
55-
res.render('general_settings', {
56-
company : company,
57-
schedule : schedule,
58-
countries : config.get('countries'),
59-
timezones_available : moment_tz.tz.names(),
60-
carryOverOptions : getAvailableCarriedOverOptions(),
61-
yearCurrent: moment.utc().year(),
62-
yearPrev: moment.utc().add(-1, 'y').year(),
63-
});
39+
const company = await req.user.getCompany({
40+
scope: ['with_leave_types'],
41+
});
42+
43+
const schedule = await company.promise_schedule();
44+
45+
res.render('general_settings', {
46+
company,
47+
schedule,
48+
countries: config.get('countries'),
49+
timezones_available: moment_tz.tz.names(),
50+
carryOverOptions: getAvailableCarriedOverOptions(),
51+
yearCurrent: moment.utc().year(),
52+
yearPrev: moment.utc().add(-1, 'y').year(),
53+
leave_types: company.leave_types.sort((a, b) => sorter(a.name, b.name)),
6454
});
6555
});
6656

public/js/global.js

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -219,40 +219,58 @@ $(document).ready(function(){
219219
});
220220

221221
$(document).ready(function() {
222-
if (typeof($.ajax) === 'function') {
223-
$.ajax({
224-
url: '/api/v1/notifications/',
225-
success: function(args){
226-
const error = args.error;
227-
const data = args.data;
228-
229-
if (error) {
230-
console.log('Failed to fetch notifications');
231-
return;
232-
}
233-
234-
if (!data || !data.length) {
235-
return;
222+
const fetchNotifications = () => {
223+
if (typeof($.ajax) === 'function') {
224+
$.ajax({
225+
url: '/api/v1/notifications/',
226+
success: function(args){
227+
const error = args.error;
228+
const data = args.data;
229+
230+
if (error) {
231+
console.log('Failed to fetch notifications');
232+
return;
233+
}
234+
235+
const dropDown = $('#header-notification-dropdown ul.dropdown-menu');
236+
const badge = $('#header-notification-dropdown .notification-badge');
237+
238+
if (!data || !data.length) {
239+
badge.addClass('hidden');
240+
dropDown.empty();
241+
dropDown.append('<li class="dropdown-header">No notifications</li>')
242+
243+
document.title = document.title.replace(/\(\d+\)\s*/, '');
244+
245+
return;
246+
}
247+
248+
const numberOfNotifications = data
249+
.map(function(d) {return d.numberOfRequests})
250+
.reduce(function(acc, it){ return acc + it}, 0)
251+
252+
badge.removeClass('hidden').html(numberOfNotifications);
253+
254+
if (!document.title.startsWith('(')) {
255+
document.title = '(' + numberOfNotifications + ') ' + document.title;
256+
} else {
257+
document.title = document.title.replace(/\(\d+\)/, '('+numberOfNotifications+')');
258+
}
259+
260+
dropDown.empty();
261+
262+
for (var i=0; i<data.length; i++) {
263+
const notification = data[i];
264+
dropDown.append(
265+
'<li><a href="'+notification.link+'">'+notification.label+'</a></li>'
266+
);
267+
}
236268
}
269+
});
270+
}
237271

238-
$('#header-notification-dropdown .notification-badge')
239-
.removeClass('hidden')
240-
.html(
241-
data
242-
.map(function(d) {return d.numberOfRequests})
243-
.reduce(function(acc, it){ return acc + it}, 0)
244-
);
245-
246-
const dropDown = $('#header-notification-dropdown ul.dropdown-menu');
247-
dropDown.empty();
248-
249-
for (var i=0; i<data.length; i++) {
250-
const notification = data[i];
251-
dropDown.append(
252-
'<li><a href="'+notification.link+'">'+notification.label+'</a></li>'
253-
);
254-
}
255-
}
256-
});
272+
setTimeout(fetchNotifications, 30 * 1000);
257273
}
274+
275+
fetchNotifications();
258276
});

t/integration/leave_request/rendering_of_halves.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ var test = require('selenium-webdriver/testing'),
1818
check_elements_func = require('../../lib/check_elements'),
1919
add_new_user_func = require('../../lib/add_new_user');
2020

21+
2122
describe('Ensure that leaves with not full days are rendered properly', function(){
2223

2324
this.timeout( config.get_execution_timeout() );
@@ -195,7 +196,7 @@ describe('Ensure that leaves with not full days are rendered properly', function
195196
value : '2015-06-11',
196197
},{
197198
selector : 'select[name="leave_type"]',
198-
option_selector : 'option[value="1"]',
199+
option_selector : 'option[data-tom-index="1"]',
199200
}],
200201
message : /New leave request was added/,
201202
})

t/integration/leave_type/crud_leave_type.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ describe('CRUD for leave types', function(){
339339
.findElements(By.css('select#leave_type option'))
340340
.then(options => Bluebird.map(options, option => {
341341
let option_info = {};
342-
return option.getAttribute('value')
342+
return option.getAttribute('data-tom-index')
343343
.then(val => Bluebird.resolve(option_info.value = val))
344344
.then(() => option.getAttribute('data-tom'))
345345
.then(txt => Bluebird.resolve(option_info.text = txt))
@@ -396,7 +396,7 @@ describe('CRUD for leave types', function(){
396396
.findElements(By.css('select#leave_type option'))
397397
.then(options => Bluebird.map(options, option => {
398398
let option_info = {};
399-
return option.getAttribute('value')
399+
return option.getAttribute('data-tom-index')
400400
.then(val => Bluebird.resolve(option_info.value = val))
401401
.then(() => option.getAttribute('data-tom'))
402402
.then(txt => Bluebird.resolve(option_info.text = txt))

t/integration/leave_type/remove_used_leave_type.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ describe('Try to remove used leave type', function(){
112112
option_selector : 'option[value="2"]',
113113
},{
114114
selector : 'select[name="leave_type"]',
115-
option_selector : 'option[value="0"]',
115+
option_selector : 'option[data-tom-index="0"]',
116116
},{
117117
selector : 'input#from',
118118
value : '2015-06-15',

views/general_settings.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,13 +202,13 @@
202202
<form id="delete_leavetype_form" method="post" action="/settings/leavetypes/delete/"></form>
203203
<form id="leave_type_edit_form" method="post" action="/settings/leavetypes/">
204204

205-
{{#unless company.leave_types.length }}
205+
{{#unless leave_types.length }}
206206
<div class="row">
207207
<div class="col-md-4">No Leave type records</div>
208208
</div>
209209
{{/unless}}
210210

211-
{{#each company.leave_types}}
211+
{{#each leave_types}}
212212
<div class="row">
213213
<div class="col-md-6">
214214

views/partials/book_leave_modal.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
<div class="form-group">
2424
<label for="leave_type" class="control-label">Leave type:</label>
2525
<select class="form-control" id="leave_type" name="leave_type">
26-
{{# each logged_user.company.leave_types}}
27-
<option value={{@index}} data-tom="{{this.name}}">{{this.name}}</option>
26+
{{#each logged_user.company.leave_types }}
27+
<option value={{this.id}} data-tom="{{this.name}}" data-tom-index={{@index}}>{{this.name}}</option>
2828
{{/each}}
2929
</select>
3030
</div>

0 commit comments

Comments
 (0)