[ADD] EMPLOYEE: New bulk selection feature in employee view

This commit is contained in:
Horilla
2023-11-01 12:19:04 +05:30
parent e8c7eddd4c
commit 7751500eb7
8 changed files with 362 additions and 91 deletions

View File

@@ -29,6 +29,16 @@ var norowMessages = {
en: "No rows have been selected.",
fr: "Aucune ligne n'a été sélectionnée.",
};
var selectedemployees = {
ar: " موظفون محددون",
de: " Ausgewählte Mitarbeiter",
es: " Empleados seleccionados",
en: " Selected Employees",
fr: " Employés sélectionnés",
};
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== "") {
@@ -63,15 +73,70 @@ $(".all-employee").change(function (e) {
} else {
$(".all-employee-row").prop("checked", false);
}
addingIds()
});
$(".all-employee").change(function (e) {
var is_checked = $(this).is(":checked");
if (is_checked) {
$(".all-employee-row").prop("checked", true);
} else {
$(".all-employee-row").prop("checked", false);
$(".all-employee-row").change(function(){
addingIds()
})
function addingIds(){
var ids = JSON.parse($("#selectedInstances").attr("data-ids") || "[]");
var selectedCount = 0;
$(".all-employee-row").each(function() {
if ($(this).is(":checked")) {
ids.push(this.id);
} else {
var index = ids.indexOf(this.id);
if (index > -1) {
ids.splice(index, 1);
}
}
});
var ids = makeListUnique(ids);
var selectedCount = ids.length;
getCurrentLanguageCode(function(code){
languageCode = code;
var message = selectedemployees[languageCode];
$("#selectedInstances").attr("data-ids", JSON.stringify(ids));
$('#selectedshow').text(selectedCount + ' -' + message);
})
}
function tickCheckboxes(uniqueIds) {
click = $("#selectedInstances").attr("data-clicked")
if ( click === '1'){
$(".all-employee").prop('checked',true)
}
});
uniqueIds.forEach(function(id) {
$('#' + id).prop('checked', true);
});
var selectedCount = uniqueIds.length;
getCurrentLanguageCode(function(code){
languageCode = code;
var message = selectedemployees[languageCode];
$('#selectedshow').text(selectedCount + ' -' + message);
})
}
function makeListUnique(list) {
return Array.from(new Set(list));
}
var ids = JSON.parse($("#selectedInstances").attr("data-ids") || "[]");
tickCheckboxes(ids);
$("#archiveEmployees").click(function (e) {
e.preventDefault();
var languageCode = null;
@@ -97,11 +162,12 @@ $("#archiveEmployees").click(function (e) {
}).then(function (result) {
if (result.isConfirmed) {
e.preventDefault();
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
ids.push($("#selectedInstances").attr("data-ids"))
ids = JSON.parse($("#selectedInstances").attr("data-ids"));
$.ajax({
type: "POST",
url: "/employee/employee-bulk-archive?is_active=False",
@@ -147,12 +213,13 @@ $("#unArchiveEmployees").click(function (e) {
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
var checkedRows = $(".all-employee-row").filter(":checked");
e.preventDefault();
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
ids.push($("#selectedInstances").attr("data-ids"))
ids = JSON.parse($("#selectedInstances").attr("data-ids"));
$.ajax({
type: "POST",
url: "/employee/employee-bulk-archive?is_active=True",
@@ -198,13 +265,13 @@ $("#deleteEmployees").click(function (e) {
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
var checkedRows = $(".all-employee-row").filter(":checked");
e.preventDefault();
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
$.ajax({
ids.push($("#selectedInstances").attr("data-ids"))
ids = JSON.parse($("#selectedInstances").attr("data-ids"));
$.ajax({
type: "POST",
url: "/employee/employee-bulk-delete",
data: {

View File

@@ -46,7 +46,9 @@
// Active tab script
function activeCandTab() {
var activeTab = localStorage.getItem("activeCandTab")
if(activeTab != null){
if (!$(activeTab).length && $(`[data-target="#personal"]`).length) {
$(`[data-target="#personal"]`)[0].click()
}else if(activeTab != null){
$(".oh-general__tab-link--active").removeClass("oh-general__tab-link--active");
$(`[data-target='${activeTab}']`).addClass("oh-general__tab-link--active");
$(".oh-general__tab-target").addClass("d-none");

View File

@@ -165,7 +165,7 @@
</div>
<div class="oh-main__titlebar oh-main__titlebar--right">
{% if data %}
{% if emp %}
<div
class="oh-input-group oh-input__search-group"
:class="searchShow ? 'oh-input__search-group--show' : ''"
@@ -187,7 +187,7 @@
aria-label="Search Input"
/>
</div>
{% endif %} {% if data %}
{% endif %} {% if emp %}
<ul class="oh-view-types ml-2" style="margin-bottom: 0">
<li class="oh-view-type employee-view-type" data-view="list">
<a
@@ -227,7 +227,7 @@
{% endif %}
<div class="oh-main__titlebar-button-container">
{% if data %}
{% if emp %}
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn ml-2" @click="open = !open">
<ion-icon name="filter" class="mr-1"></ion-icon>{% trans "Filter" %}
@@ -283,39 +283,38 @@
>{% trans "Import" %}</a
>
</li>
{% if data %}
<li class="oh-dropdown__item">
<a
href="#"
class="oh-dropdown__link"
id="employee-info-export"
data-toggle="oh-modal-toggle"
data-target="#employeeExport"
>{% trans "Export" %}</a
>
</li>
{% if perms.delete_employee %}
<li class="oh-dropdown__item">
<a href="#" class="oh-dropdown__link" id="archiveEmployees"
>{% trans "Archive" %}</a
>
</li>
{% endif %} {% if perms.delete_employee %}
<li class="oh-dropdown__item">
<a href="#" class="oh-dropdown__link" id="unArchiveEmployees"
>{% trans "Un-Archive" %}</a
>
</li>
{% endif %} {% if perms.delete_employee %}
<li class="oh-dropdown__item">
<a
href="#"
class="oh-dropdown__link oh-dropdown__link--danger"
id="deleteEmployees"
>{% trans "Delete" %}</a
>
</li>
{% endif %} {% endif %}
{% if emp %}
<li class="oh-dropdown__item">
<a
href="#"
class="oh-dropdown__link"
id="employee-info-export"
data-toggle="oh-modal-toggle"
data-target="#employeeExport"
>{% trans "Export" %}</a
>
</li>
<li class="oh-dropdown__item">
<a href="#" class="oh-dropdown__link" id="archiveEmployees"
>{% trans "Archive" %}</a
>
</li>
<li class="oh-dropdown__item">
<a href="#" class="oh-dropdown__link" id="unArchiveEmployees"
>{% trans "Un-Archive" %}</a
>
</li>
{% if perms.delete_employee %}
<li class="oh-dropdown__item">
<a
href="#"
class="oh-dropdown__link oh-dropdown__link--danger"
id="deleteEmployees"
>{% trans "Delete" %}</a
>
</li>
{% endif %}
{% endif %}
</ul>
</div>
</div>

View File

@@ -2,32 +2,38 @@
{% load static %} {% load i18n %}
<div id="view-container">
{% if messages %}
<div class="oh-alert-container">
{% for message in messages %}
<div class="oh-alert oh-alert--animated {{message.tags}}">{{ message }}</div>
{% endfor %}
</div>
{% endif %}
{% include 'filter_tags.html' %}
<div id="view-container">
{% if messages %}
<div class="oh-alert-container">
{% for message in messages %}
<div class="oh-alert oh-alert--animated {{message.tags}}">{{ message }}</div>
{% endfor %}
</div>
{% endif %}
{% include 'filter_tags.html' %}
<div class="oh-checkpoint-badge text-success mb-2" id="selectAllInstances" style="cursor: pointer;">
{% trans "Select All Employees" %}
</div>
<div class="oh-checkpoint-badge text-primary mb-2" id="unselectAllInstances" style="cursor: pointer;">
{% trans "Unselect All Employees" %}
</div>
<div class="oh-checkpoint-badge text-danger mb-2" id="selectedshow" >
</div>
<div class="oh-sticky-table">
<div class="oh-sticky-table__table oh-table--sortable">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th">
<div class="d-flex">
<div class="">
<input
type="checkbox"
class="oh-input oh-input__checkbox mt-1 mr-2 all-employee"
title='{% trans "Select All" %}'
/>
</div>
<div hx-target="#view-container" hx-get="{% url 'employee-view-list' %}?{{pd}}&orderby=employee_first_name">
{% trans "Employee" %}
</div>
</div>
<div class="oh-sticky-table__th" style="width:10px;">
<input
type="checkbox"
class="oh-input oh-input__checkbox mt-1 all-employee"
title='{% trans "Select All" %}'
style="margin-left:-5px;"
id="tick"
/>
</div>
<div class="oh-sticky-table__th" hx-target="#view-container" hx-get="{% url 'employee-view-list' %}?{{pd}}&orderby=employee_first_name">
{% trans "Employee" %}
</div>
<div class="oh-sticky-table__th">{% trans "Email" %}</div>
<div class="oh-sticky-table__th">{% trans "Phone" %}</div>
@@ -48,14 +54,16 @@
<div class="oh-sticky-table__tbody ui-sortable">
<div class="oh-sticky-table__tr ui-sortable-handle">
<div class="oh-sticky-table__sd">
<div class="">
<input
type="checkbox"
id="{{emp.id}}"
class="oh-input employee-checkbox oh-input__checkbox mt-2 mr-2 all-employee-row"
/>
</div>
</div>
<div class="oh-sticky-table__td">
<div class="d-flex">
<div class="">
<input
type="checkbox"
id="{{emp.id}}"
class="oh-input employee-checkbox oh-input__checkbox mt-2 mr-2 all-employee-row"
/>
</div>
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
{% if emp.employee_profile %}
@@ -185,7 +193,7 @@
class="oh-btn oh-btn--danger-outline oh-btn--light-bkg w-100"
title="{% trans 'Un-Archive' %}"
>
<ion-icon name="Un-Archive"></ion-icon>
<ion-icon name="archive"></ion-icon>
</button>
</form>
{% endif %}
@@ -240,6 +248,7 @@
hx-target="#view-container"
hx-get="{% url 'employee-view-list' %}?{{pd}}&page=1"
class="oh-pagination__link"
onclick=tickCheckboxes()
>{% trans "First" %}</a
>
</li>
@@ -248,6 +257,7 @@
hx-target="#view-container"
hx-get="{% url 'employee-view-list' %}?{{pd}}&page={{ data.previous_page_number }}"
class="oh-pagination__link"
onclick=tickCheckboxes()
>{% trans "Previous" %}</a
>
</li>
@@ -257,6 +267,7 @@
hx-target="#view-container"
hx-get="{% url 'employee-view-list' %}?{{pd}}&page={{ data.next_page_number }}"
class="oh-pagination__link"
onclick=tickCheckboxes()
>{% trans "Next" %}</a
>
</li>
@@ -265,6 +276,7 @@
hx-target="#view-container"
hx-get="{% url 'employee-view-list' %}?{{pd}}&page={{ data.paginator.num_pages }}"
class="oh-pagination__link"
onclick=tickCheckboxes()
>{% trans "Last" %}</a
>
</li>
@@ -277,3 +289,133 @@
<script src="{% static 'employee/actions.js' %}"></script>
<script>
$(document).ready(function() {
$('#selectAllInstances').click(function() {
$("#selectedInstances").attr("data-clicked", 1);
$('#selectedshow').removeAttr('style');
var savedFilters = JSON.parse(localStorage.getItem('savedFilters'));
if (savedFilters && savedFilters['filterData'] !== null)
{
var filter = savedFilters['filterData'];
$.ajax({
url: '{% url "employee-select-filter" %}',
data: { page: 'all', 'filter':JSON.stringify(filter) },
type: 'GET',
dataType: 'json',
success: function(response) {
var employeeIds = response.employee_ids;
if (Array.isArray(employeeIds)) {
// Continue
} else {
console.error('employee_ids is not an array:', employeeIds);
}
var selectedCount = employeeIds.length;
for (var i = 0; i < employeeIds.length; i++) {
var empId = employeeIds[i];
$('#' + empId).prop('checked', true);
}
$("#selectedInstances").attr("data-ids", JSON.stringify(employeeIds));
count = makeListUnique(employeeIds)
tickCheckboxes(count)
},
error: function(xhr, status, error) {
console.error('Error:', error);
}
});
}
else {
$.ajax({
url: '{% url "employee-select" %}',
data: { page: 'all'},
type: 'GET',
dataType: 'json',
success: function(response) {
var employeeIds = response.employee_ids;
if (Array.isArray(employeeIds)) {
// Continue
} else {
console.error('employee_ids is not an array:', employeeIds);
}
var selectedCount = employeeIds.length;
for (var i = 0; i < employeeIds.length; i++) {
var empId = employeeIds[i];
$('#' + empId).prop('checked', true);
}
$("#selectedInstances").attr("data-ids", JSON.stringify(employeeIds));
count = makeListUnique(employeeIds)
tickCheckboxes(count)
},
error: function(xhr, status, error) {
console.error('Error:', error);
}
});
}
$('.filterButton').click(function(){
$("#tick").prop('checked', false);
$("#selectedInstances").attr("data-clicked", 0);
$("#selectedInstances").attr("data-ids", JSON.stringify([]));
count = [];
tickCheckboxes(count)
})
});
$('#unselectAllInstances').click(function(){
$("#selectedInstances").attr("data-clicked", 0);
$.ajax({
url: '{% url "employee-select" %}',
data: { page: 'all', 'filter': '{}' },
type: 'GET',
dataType: 'json',
success: function(response) {
var employeeIds = response.employee_ids;
if (Array.isArray(employeeIds)) {
// Continue
} else {
console.error('employee_ids is not an array:', employeeIds);
}
for (var i = 0; i < employeeIds.length; i++) {
var empId = employeeIds[i];
$('#' + empId).prop('checked', false);
$("#tick").prop('checked', false);
}
$("#selectedInstances").attr("data-ids", JSON.stringify([]));
count = [];
tickCheckboxes(count)
},
error: function(xhr, status, error) {
console.error('Error:', error);
}
});
});
});
</script>

View File

@@ -1,5 +1,8 @@
{% extends "index.html" %} {% block content %} {% include 'employee_nav.html' %}
{% extends "index.html" %} {% load static %} {% load i18n %} {% block content %} {% include 'employee_nav.html' %}
<div class="oh-wrapper">
<div class="oh-checkpoint-badge mb-2" id="selectedInstances" data-ids="[]" data-clicked="" style="display:none;" >
{% trans "Selected Employees" %}
</div>
<div id="view-container">
{% if data %}
{% if view_type == 'list' %}
@@ -12,4 +15,5 @@
{% endif %}
</div>
</div>
<script src="{% static 'employee/actions.js' %}"></script>
{% endblock %}

View File

@@ -184,7 +184,7 @@
</div>
<div class="oh-sticky-table__td">{% with month=ot.month|capfirst %}{% trans month %}{% endwith %}</div>
<div class="oh-sticky-table__td">{{ot.year}}</div>
<div class="oh-sticky-table__td">{{ot.hour_account}}</div>
<div class="oh-sticky-table__td">{{ot.worked_hours}}</div>
<div class="oh-sticky-table__td">{{ot.overtime}}</div>
<div class="oh-sticky-table__td">
<div class="oh-btn-group">

View File

@@ -163,4 +163,7 @@ urlpatterns = [
path("attendance-tab/<int:emp_id>", views.attendance_tab, name="attendance-tab"),
path("shift-tab/<int:emp_id>", views.shift_tab, name="shift-tab"),
path("contract-tab/<int:obj_id>", views.contract_tab, name="contract-tab"),
path('employee-select/', views.employee_select, name='employee-select'),
path('employee-select-filter/', views.employee_select_filter, name='employee-select-filter'),
]

View File

@@ -18,6 +18,7 @@ from datetime import datetime, timedelta, date
from collections import defaultdict
from urllib.parse import parse_qs
import pandas as pd
from django.db.models import Q
from django.db.models import F, ProtectedError
from django.conf import settings
from django.contrib import messages
@@ -382,6 +383,7 @@ def employee_view(request):
)
data_dict = parse_qs(previous_data)
get_key_instances(Employee, data_dict)
emp = Employee.objects.all()
return render(
request,
"employee_personal_info/employee_view.html",
@@ -393,6 +395,7 @@ def employee_view(request):
"export_form": export_form,
"view_type": view_type,
"filter_dict": data_dict,
"emp":emp
},
)
@@ -1648,3 +1651,54 @@ def widget_filter(request):
"""
ids = EmployeeFilter(request.GET).qs.values_list("id", flat=True)
return JsonResponse({"ids": list(ids)})
@login_required
def employee_select(request):
page_number = request.GET.get('page')
if page_number == 'all':
employees = Employee.objects.all()
else:
employees = Employee.objects.all().order_by('employee_first_name')
paginator = Paginator(employees, per_page=50)
page_obj = paginator.get_page(page_number)
employee_ids = [str(emp.id) for emp in employees]
total_count = employees.count()
context = {
'employee_ids': employee_ids,
'total_count': total_count
}
return JsonResponse(context, safe=False)
@login_required
def employee_select_filter(request):
page_number = request.GET.get('page')
filtered = request.GET.get('filter')
filters = json.loads(filtered) if filtered else {}
if page_number == 'all':
query = Q()
for key, value in filters.items():
if value != '' and key != 'is_active': # Add check for is_active and non-empty values
kwargs = {key: value}
query &= Q(**kwargs)
elif key == 'is_active' and value in ['true', 'false']: # Check if is_active is valid
kwargs = {key: value == 'true'} # Convert 'true' to True, 'false' to False
query &= Q(**kwargs)
employees = Employee.objects.filter(query)
employee_ids = [str(emp.id) for emp in employees]
total_count = employees.count()
context = {
'employee_ids': employee_ids,
'total_count': total_count
}
return JsonResponse(context)