[IMP] hr_holidays,web: Improve the mobile view for calendar and times off

Purpose of the task is to improve mobile interface of the Time Off
and calendar view.

So in this commit, we have improved UI as below:
hr_holidays:
 - Move the leave summary topbar from top to sidebar filter of
calendar for small screen
 - Improve the kanban view of leave for mobile and added the
badge for state.

web:
 - Improve the calendar year mobile view by spliting the month view
in 2 column.

TaskID: 2333778
Related PR: https://github.com/odoo/enterprise/pull/13454

closes odoo/odoo#61474

Related: odoo/enterprise#13454
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
Mithilesh Rao
2021-02-08 08:35:05 +00:00
committed by Yannick Tivisse
parent c146e63779
commit 6cd42e016d
7 changed files with 92 additions and 53 deletions
+1 -1
View File
@@ -256,7 +256,7 @@ class HolidaysType(models.Model):
'leaves_taken': ('%.2f' % lt.leaves_taken).rstrip('0').rstrip('.'),
'virtual_leaves_taken': ('%.2f' % lt.virtual_leaves_taken).rstrip('0').rstrip('.'),
'request_unit': lt.request_unit,
}, lt.allocation_type, lt.validity_stop)
}, lt.allocation_type, lt.validity_stop, lt.id)
for lt in leave_types]
def _get_contextual_employee_id(self):
@@ -2,6 +2,7 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
'use strict';
var core = require('web.core');
const config = require('web.config');
var CalendarPopover = require('web.CalendarPopover');
var CalendarController = require("web.CalendarController");
var CalendarRenderer = require("web.CalendarRenderer");
@@ -171,10 +172,19 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
// Do not display header if there is no element to display
if (result.length > 0) {
var elem = QWeb.render('hr_holidays.dashboard_calendar_header', {
timeoffs: result,
});
self.$el.before(elem);
if (config.device.isMobile) {
result.forEach((data) => {
const elem = QWeb.render('hr_holidays.dashboard_calendar_header_mobile', {
timeoff: data,
});
self.$el.find('.o_calendar_filter_item[data-value=' + data[4] + '] .o_cw_filter_title').append(elem);
});
} else {
const elem = QWeb.render('hr_holidays.dashboard_calendar_header', {
timeoffs: result,
});
self.$el.before(elem);
}
}
});
},
@@ -11,16 +11,6 @@
height: 100%;
}
@include media-breakpoint-down(sm) {
.o_timeoff_container {
height: 15%;
}
.o_calendar_container {
height: 85%;
}
}
.o_timeoff_card {
border-right: #adb5bd solid 2px;
text-align: center;
@@ -30,6 +30,24 @@
</div>
</t>
<t t-name="hr_holidays.dashboard_calendar_header_mobile">
<t t-set="need_allocation" t-value="timeoff[2] !== 'no'"/>
<span class="pull-right">
<span>
<t t-if="need_allocation">
<strong t-esc="timeoff[1]['virtual_remaining_leaves']" class="o_timeoff_green"/> / <span t-esc="timeoff[1]['max_leaves']"/>
<t t-if="timeoff[1]['request_unit'] == 'hour'">Hours</t><t t-else="">Days</t><span class="o_timeoff_green ml-2">Available </span>
</t>
<t t-else="">
<strong t-esc="timeoff[1]['virtual_leaves_taken']"/> <t t-if="timeoff[1]['request_unit'] == 'hour'">Hours</t><t t-else="">Days</t><span class="o_timeoff_purple ml-2">Taken</span>
</t>
</span>
<span t-if="need_allocation">
<t t-if="timeoff[3]"> (Expire on <span t-esc="moment(timeoff[3]).format('L')"/>)</t>
</span>
</span>
</t>
<t t-name="hr_holidays.dashboard.calendar.button">
<button class="btn btn-primary btn-time-off" type="button">
<t t-esc="time_off"/>
@@ -296,13 +296,13 @@
<t t-name="kanban-box">
<div class="oe_kanban_global_click container">
<div class="row no-gutters">
<div class="col-2">
<div class="col-3">
<img t-att-src="kanban_image('hr.employee', 'image_128', record.employee_id.raw_value)"
t-att-title="record.employee_id.value"
t-att-alt="record.employee_id.value"
class="oe_kanban_avatar o_image_40_cover float-left mr4"/>
class="o_image_64_cover float-left mr4"/>
</div>
<div class="col-10">
<div class="col-9">
<span class="badge badge-pill float-right mt4 mr16"><t t-esc="record.number_of_days.value"/> days</span>
<strong class="o_kanban_record_title"><t t-esc="record.employee_id.value"/></strong>
<div class="text-muted o_kanban_record_subtitle">
@@ -317,21 +317,23 @@
<a t-if="widget.deletable" role="menuitem" type="delete" class="dropdown-item">Delete</a>
</div>
</div>
</div>
</div>
<div class="row no-gutters" t-if="['validate', 'refuse'].includes(record.state.raw_value)">
<div class="col-2"/>
<div class="col-10">
<span t-if="record.state.raw_value === 'validate'" class="fa fa-check text-muted" aria-label="validated"/>
<span t-else="" class="fa fa-ban text-muted" aria-label="refused"/>
<span class="text-muted"><t t-esc="record.state.value"/></span>
</div>
</div>
<div class="o_kanban_record_bottom" t-if="record.can_approve.raw_value" >
<div class="oe_kanban_bottom_left" t-if="record.can_approve.raw_value">
<button t-if="record.state.raw_value === 'confirm'" name="action_approve" type="object" class="btn btn-primary btn-sm mt8">Approve</button>
<button t-if="record.state.raw_value === 'validate1'" name="action_validate" type="object" class="btn btn-primary btn-sm mt8">Validate</button>
<button t-if="['confirm', 'validate1'].includes(record.state.raw_value)" name="action_refuse" type="object" class="btn btn-secondary btn-sm mt8">Refuse</button>
<div t-if="['validate', 'refuse'].includes(record.state.raw_value)">
<span t-if="record.state.raw_value === 'validate'" class="fa fa-check text-muted" aria-label="validated"/>
<span t-else="" class="fa fa-ban text-muted" aria-label="refused"/>
<t t-set="classname" t-value="{'validate': 'badge-success', 'refuse': 'badge-danger'}[record.state.raw_value] || 'badge-light'"/>
<span t-attf-class="badge badge-pill {{ classname }}"><t t-esc="record.state.value"/></span>
</div>
<div t-if="record.can_approve.raw_value">
<button t-if="record.state.raw_value === 'confirm'" name="action_approve" type="object" class="btn btn-link btn-sm pl-0">
<i class="fa fa-thumbs-up"/> Approve
</button>
<button t-if="record.state.raw_value === 'validate1'" name="action_validate" type="object" class="btn btn-link btn-sm pl-0">
<i class="fa fa-check"/> Validate
</button>
<button t-if="['confirm', 'validate1'].includes(record.state.raw_value)" name="action_refuse" type="object" class="btn btn-link btn-sm pl-0">
<i class="fa fa-times"/> Refuse
</button>
</div>
</div>
</div>
</div>
+25 -20
View File
@@ -108,13 +108,13 @@
<t t-name="kanban-box">
<div class="oe_kanban_global_click container">
<div class="row no-gutters">
<div class="col-2">
<div class="col-3">
<img t-att-src="kanban_image('hr.employee', 'image_128', record.employee_id.raw_value)"
t-att-title="record.employee_id.value"
t-att-alt="record.employee_id.value"
class="oe_kanban_avatar o_image_40_cover float-left mr4"/>
class="o_image_64_cover float-left mr4"/>
</div>
<div class="col-10">
<div class="col-9">
<span class="badge badge-pill float-right mt4 mr16"><t t-esc="record.number_of_days.value"/> days</span>
<strong class="o_kanban_record_title"><t t-esc="record.employee_id.value"/></strong>
<div class="text-muted o_kanban_record_subtitle">
@@ -129,30 +129,35 @@
<a t-if="widget.deletable" role="menuitem" type="delete" class="dropdown-item">Delete</a>
</div>
</div>
</div>
</div>
<div class="row no-gutters justify-content-end">
<div class="col-2"/>
<div class="col-10">
<span class="text-muted">from </span>
<field name="date_from" widget="date"/>
<span class="text-muted">to </span>
<field name="date_to" widget="date"/>
<div>
<span class="text-muted">from </span>
<field name="date_from" widget="date"/>
<span class="text-muted">to </span>
<field name="date_to" widget="date"/>
</div>
</div>
</div>
<div class="row no-gutters" t-if="['validate', 'refuse'].includes(record.state.raw_value)">
<div class="col-2"/>
<div class="col-10">
<div class="col-3"/>
<div class="col-9">
<span t-if="record.state.raw_value === 'validate'" class="fa fa-check text-muted" aria-label="validated"/>
<span t-else="" class="fa fa-ban text-muted" aria-label="refused"/>
<span class="text-muted"><t t-esc="record.state.value"/></span>
<t t-set="classname" t-value="{'validate': 'badge-success', 'refuse': 'badge-danger'}[record.state.raw_value] || 'badge-light'"/>
<span t-attf-class="badge badge-pill {{ classname }}"><t t-esc="record.state.value"/></span>
</div>
</div>
<div class="o_kanban_record_bottom" t-if="record.can_approve.raw_value">
<div class="oe_kanban_bottom_left">
<button t-if="record.state.raw_value === 'confirm'" name="action_approve" type="object" class="btn btn-primary btn-sm mt8">Approve</button>
<button t-if="record.state.raw_value === 'validate1'" name="action_validate" type="object" class="btn btn-primary btn-sm mt8" groups="hr_holidays.group_hr_holidays_manager">Validate</button>
<button t-if="['confirm', 'validate1'].includes(record.state.raw_value)" name="action_refuse" type="object" class="btn btn-secondary btn-sm mt8">Refuse</button>
<div class="row no-gutters" t-if="record.can_approve.raw_value">
<div class="col-3"/>
<div class="col=9" t-if="['confirm', 'validate1'].includes(record.state.raw_value)">
<button t-if="record.state.raw_value === 'confirm'" name="action_approve" type="object" class="btn btn-link btn-sm pl-0">
<i class="fa fa-thumbs-up"/> Approve
</button>
<button t-if="record.state.raw_value === 'validate1'" name="action_validate" type="object" class="btn btn-link btn-sm pl-0" groups="hr_holidays.group_hr_holidays_manager">
<i class="fa fa-check"/> Validate
</button>
<button t-if="['confirm', 'validate1'].includes(record.state.raw_value)" name="action_refuse" type="object" class="btn btn-link btn-sm pl-0">
<i class="fa fa-times"/> Refuse
</button>
</div>
</div>
</div>
@@ -340,6 +340,11 @@ $o-cw-filter-avatar-size: 20px;
justify-content: space-evenly;
overflow-y: auto;
@include media-breakpoint-down(sm) {
padding-right: 5px;
padding-left: 5px;
}
> table {
height: 100%;
}
@@ -369,10 +374,19 @@ $o-cw-filter-avatar-size: 20px;
min-width: 25rem;
box-sizing: border-box;
@include media-breakpoint-down(sm) {
width: 50%;
min-width: 12rem;
}
> .fc-month {
width: 21rem;
margin: auto;
@include media-breakpoint-down(sm) {
width: 95%;
}
> .fc-toolbar.fc-header-toolbar {
margin-top: 10px;
margin-bottom: 4px;