[UPDT] DASHBOARD: Main dashboard design updates
This commit is contained in:
@@ -3,11 +3,10 @@ from typing import Any
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from horilla_views.cbv_methods import login_required, permission_required
|
||||
from horilla_views.generic.cbv.views import HorillaDetailedView, HorillaListView
|
||||
|
||||
from asset.filters import AssetFilter
|
||||
from asset.models import Asset
|
||||
from horilla_views.cbv_methods import login_required, permission_required
|
||||
from horilla_views.generic.cbv.views import HorillaDetailedView, HorillaListView
|
||||
|
||||
|
||||
@method_decorator(login_required, name="dispatch")
|
||||
|
||||
@@ -33,4 +33,4 @@
|
||||
<ion-icon name="trash-outline" role="img" class="md hydrated" aria-label="trash outline"></ion-icon>
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -24,4 +24,4 @@
|
||||
</button>
|
||||
</form>
|
||||
<!-- End of Delete Form -->
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -54,7 +54,7 @@ class DashboardOfflineEmployees(HorillaListView):
|
||||
style="width:80px !important;"
|
||||
""",
|
||||
}
|
||||
records_per_page = 7
|
||||
records_per_page = 5
|
||||
show_toggle_form = False
|
||||
bulk_select_option = False
|
||||
|
||||
@@ -85,7 +85,7 @@ class DashboardOnlineEmployees(HorillaListView):
|
||||
return queryset
|
||||
|
||||
columns = [
|
||||
("Employee", "employee_id__get_full_name", "employee_id__get_avatar"),
|
||||
("Employee", "get_full_name", "get_avatar"),
|
||||
("Work Status", "get_custom_forecasted_info_col"),
|
||||
]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,41 +1,41 @@
|
||||
$(document).ready(function () {
|
||||
function employeeChart(dataSet, labels) {
|
||||
const data = {
|
||||
labels: labels,
|
||||
datasets: dataSet,
|
||||
};
|
||||
// Create chart using the Chart.js library
|
||||
window["myChart"] = {};
|
||||
if (document.getElementById("totalEmployees")) {
|
||||
const ctx = document.getElementById("totalEmployees").getContext("2d");
|
||||
employeeChart = new Chart(ctx, {
|
||||
type: "doughnut",
|
||||
data: data,
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
onClick: (e, activeEls) => {
|
||||
let datasetIndex = activeEls[0].datasetIndex;
|
||||
let dataIndex = activeEls[0].index;
|
||||
let datasetLabel = e.chart.data.datasets[datasetIndex].label;
|
||||
let value = e.chart.data.datasets[datasetIndex].data[dataIndex];
|
||||
let label = e.chart.data.labels[dataIndex];
|
||||
var active = "False";
|
||||
if (label.toLowerCase() == "active") {
|
||||
active = "True";
|
||||
}
|
||||
localStorage.removeItem("savedFilters");
|
||||
window.location.href = "/employee/employee-view?is_active=" + active;
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
afterRender: (chart) => emptyChart(chart),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
// function employeeChart(dataSet, labels) {
|
||||
// const data = {
|
||||
// labels: labels,
|
||||
// datasets: dataSet,
|
||||
// };
|
||||
// // Create chart using the Chart.js library
|
||||
// window["myChart"] = {};
|
||||
// if (document.getElementById("totalEmployees")) {
|
||||
// const ctx = document.getElementById("totalEmployees").getContext("2d");
|
||||
// employeeChart = new Chart(ctx, {
|
||||
// type: "doughnut",
|
||||
// data: data,
|
||||
// options: {
|
||||
// responsive: true,
|
||||
// maintainAspectRatio: false,
|
||||
// onClick: (e, activeEls) => {
|
||||
// let datasetIndex = activeEls[0].datasetIndex;
|
||||
// let dataIndex = activeEls[0].index;
|
||||
// let datasetLabel = e.chart.data.datasets[datasetIndex].label;
|
||||
// let value = e.chart.data.datasets[datasetIndex].data[dataIndex];
|
||||
// let label = e.chart.data.labels[dataIndex];
|
||||
// var active = "False";
|
||||
// if (label.toLowerCase() == "active") {
|
||||
// active = "True";
|
||||
// }
|
||||
// localStorage.removeItem("savedFilters");
|
||||
// window.location.href = "/employee/employee-view?is_active=" + active;
|
||||
// },
|
||||
// },
|
||||
// plugins: [
|
||||
// {
|
||||
// afterRender: (chart) => emptyChart(chart),
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
// function genderChart(dataSet, labels) {
|
||||
// const data = {
|
||||
@@ -111,6 +111,131 @@ $(document).ready(function () {
|
||||
// }
|
||||
// }
|
||||
|
||||
function employeeChart(dataSet, labels) {
|
||||
$(document).ready(function () {
|
||||
const ctx = document.getElementById("totalEmployees")?.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
const values = dataSet[0].data;
|
||||
const colors = [
|
||||
"#34d399", // Active - green
|
||||
"#f87171", // Inactive - red
|
||||
];
|
||||
const visibility = Array(labels.length).fill(true);
|
||||
|
||||
// Create chart instance
|
||||
const employeeChartInstance = new Chart(ctx, {
|
||||
type: "doughnut",
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [
|
||||
{
|
||||
...dataSet[0],
|
||||
backgroundColor: colors.slice(0, labels.length),
|
||||
borderWidth: 0,
|
||||
borderRadius: 10,
|
||||
hoverOffset: 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
cutout: "70%",
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
onClick: function (e, activeEls) {
|
||||
if (!activeEls.length) return;
|
||||
|
||||
const dataIndex = activeEls[0].index;
|
||||
const label = labels[dataIndex];
|
||||
let active = label.toLowerCase() === "active" ? "True" : "False";
|
||||
|
||||
localStorage.removeItem("savedFilters");
|
||||
window.location.href = "/employee/employee-view?is_active=" + active;
|
||||
},
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
tooltip: {
|
||||
backgroundColor: "#111827",
|
||||
bodyColor: "#f3f4f6",
|
||||
borderColor: "#e5e7eb",
|
||||
borderWidth: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
id: "centerText",
|
||||
afterDraw(chart) {
|
||||
const { width, height, ctx } = chart;
|
||||
ctx.save();
|
||||
|
||||
const total = chart.data.datasets[0].data.reduce(
|
||||
(sum, val) => sum + val,
|
||||
0
|
||||
);
|
||||
|
||||
ctx.font = "bold 22px sans-serif";
|
||||
ctx.fillStyle = "#374151";
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText(total, width / 2, height / 2 - 5);
|
||||
|
||||
ctx.font = "15px sans-serif";
|
||||
ctx.fillStyle = "#9ca3af";
|
||||
ctx.fillText("Total", width / 2, height / 2 + 20);
|
||||
|
||||
ctx.restore();
|
||||
},
|
||||
},
|
||||
{
|
||||
afterRender: (chart) => {
|
||||
if (typeof emptyChart === "function") {
|
||||
emptyChart(chart);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 🧩 Custom Legend Generation
|
||||
const $legendContainer = $("#employeeChartLegend"); // Make sure to have this element in DOM
|
||||
$legendContainer.empty();
|
||||
|
||||
labels.forEach((label, index) => {
|
||||
const color = colors[index % colors.length];
|
||||
|
||||
const $item = $(`
|
||||
<div style="display: flex; align-items: center; margin-bottom: 6px; cursor: pointer;">
|
||||
<span style="display: inline-block; width: 12px; height: 12px; border-radius: 50%; background-color: ${color}; margin-right: 8px;"></span>
|
||||
<span class="legend-label">${label}</span>
|
||||
</div>
|
||||
`);
|
||||
|
||||
$legendContainer.append($item);
|
||||
|
||||
$item.on("click", function () {
|
||||
visibility[index] = !visibility[index];
|
||||
|
||||
employeeChartInstance.data.datasets[0].data = values.map((val, i) =>
|
||||
visibility[i] ? val : 0
|
||||
);
|
||||
|
||||
const $dot = $(this).find("span").first();
|
||||
const $label = $(this).find(".legend-label");
|
||||
|
||||
if (visibility[index]) {
|
||||
$dot.css("opacity", "1");
|
||||
$label.css("text-decoration", "none");
|
||||
} else {
|
||||
$dot.css("opacity", "0.4");
|
||||
$label.css("text-decoration", "line-through");
|
||||
}
|
||||
|
||||
employeeChartInstance.update();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function genderChart(dataSet, labels) {
|
||||
const centerImage = new Image();
|
||||
@@ -200,8 +325,6 @@ $(document).ready(function () {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function departmentChart(dataSet, labels) {
|
||||
$(document).ready(function () {
|
||||
const ctx = $("#departmentChart")[0]?.getContext("2d");
|
||||
@@ -324,8 +447,6 @@ $(document).ready(function () {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
$.ajax({
|
||||
url: "/employee/dashboard-employee",
|
||||
type: "GET",
|
||||
|
||||
@@ -1814,6 +1814,17 @@ ul.errorlist ul.errorlist li {
|
||||
background: #00d6ff1f !important;
|
||||
}
|
||||
|
||||
|
||||
.oh-recuritment_tag {
|
||||
background-color: hsl(0, 75%, 97%);
|
||||
color: hsl(1, 100%, 61%);
|
||||
padding: 0.4rem 0.6rem;
|
||||
border-radius: 0.2rem;
|
||||
margin-right: 0.2rem;
|
||||
font-size: 0.8rem;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
/* SIDEBAR */
|
||||
|
||||
.sidebarModal {
|
||||
|
||||
@@ -25,4 +25,3 @@
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
|
||||
|
||||
@@ -89,8 +89,8 @@
|
||||
<div class="w-full overflow-x-auto overflow-y-auto" id="shiftRequestApprove" hx-get="{% url 'dashboard-shift-request' %}" hx-trigger="load">
|
||||
</div>
|
||||
</div>
|
||||
{% comment %} {% if not 'gender_chart' in charts %} {% endcomment %}
|
||||
{% comment %} {% if 'gender_chart'|feature_is_accessible:request or perms.employee.view_employee or request.user|is_reportingmanager %} {% endcomment %}
|
||||
{% if not 'gender_chart' in charts %}
|
||||
{% if 'gender_chart'|feature_is_accessible:request or perms.employee.view_employee or request.user|is_reportingmanager %}
|
||||
<div class="xl:col-span-3 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Gender Chart" %}</h3>
|
||||
@@ -101,8 +101,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% comment %} {% endif %} {% endcomment %}
|
||||
{% comment %} {% endif %} {% endcomment %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<div class="xl:col-span-3 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
@@ -202,9 +202,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Recent Activities -->
|
||||
{% comment %} {% if "pms"|app_installed and not 'key_result_status' in charts %} {% endcomment %}
|
||||
{% comment %} {% if perms.pms.view_employeekeyresult or request.user|is_reportingmanager %} {% endcomment %}
|
||||
|
||||
{% if "pms"|app_installed and not 'key_result_status' in charts %}
|
||||
{% if perms.pms.view_employeekeyresult or request.user|is_reportingmanager %}
|
||||
<div class="xl:col-span-3 md:col-span-5 col-span-12 bg-white p-6 rounded-md shadow-card" style="width:98%;">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Key Result Status" %}</h3>
|
||||
@@ -213,8 +212,8 @@
|
||||
<canvas id="keyResultChart" style="cursor: pointer"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
{% comment %} {% endif %} {% endcomment %}
|
||||
{% comment %} {% endif %} {% endcomment %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<div class="xl:col-span-5 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
@@ -253,280 +252,226 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if "leave"|app_installed %}
|
||||
{% if perms.leave.view_leaverequest or request.user|is_reportingmanager %}
|
||||
<div class="xl:col-span-3 md:col-span-4 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "On Leave" %}</h3>
|
||||
</div>
|
||||
<div class="flex-col items-center justify-center" hx-get="{% url 'employee-leave' %}" hx-trigger="load">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="xl:col-span-5 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">Offline Employees</h3>
|
||||
</div>
|
||||
<div class="overflow-hidden overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<th class="text-sm font-medium text-left p-3 pl-0">
|
||||
<span class="flex w-max">Employee</span>
|
||||
</th>
|
||||
<th class="text-sm font-medium text-left p-3 pl-0">
|
||||
<span class="flex w-max">Mail</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
<button class="cursor-pointer px-2.5 py-1 bg-[#00c49025] text-[#00C490] rounded-sm text-xs">
|
||||
Expected working
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-xs text-left p-3 pl-0 text-[#666]">
|
||||
<button class="cursor-pointer">
|
||||
<img src="/static/horilla_theme/assets/img/icons/email.svg" alt="" width="25" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
<button class="cursor-pointer px-2.5 py-1 bg-[#00c49025] text-[#00C490] rounded-sm text-xs">
|
||||
Expected working
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-xs text-left p-3 pl-0 text-[#666]">
|
||||
<button class="cursor-pointer">
|
||||
<img src="/static/horilla_theme/assets/img/icons/email.svg" alt="" width="25" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
<button class="cursor-pointer px-2.5 py-1 bg-[#00c49025] text-[#00C490] rounded-sm text-xs">
|
||||
Expected working
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-xs text-left p-3 pl-0 text-[#666]">
|
||||
<button class="cursor-pointer">
|
||||
<img src="/static/horilla_theme/assets/img/icons/email.svg" alt="" width="25" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
<button class="cursor-pointer px-2.5 py-1 bg-[#00c49025] text-[#00C490] rounded-sm text-xs">
|
||||
Expected working
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-xs text-left p-3 pl-0 text-[#666]">
|
||||
<button class="cursor-pointer">
|
||||
<img src="/static/horilla_theme/assets/img/icons/email.svg" alt="" width="25" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
<button class="cursor-pointer px-2.5 py-1 bg-[#00c49025] text-[#00C490] rounded-sm text-xs">
|
||||
Expected working
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-xs text-left p-3 pl-0 text-[#666]">
|
||||
<button class="cursor-pointer">
|
||||
<img src="/static/horilla_theme/assets/img/icons/email.svg" alt="" width="25" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
<button class="cursor-pointer px-2.5 py-1 bg-[#00c49025] text-[#00C490] rounded-sm text-xs">
|
||||
Expected working
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-xs text-left p-3 pl-0 text-[#666]">
|
||||
<button class="cursor-pointer">
|
||||
<img src="/static/horilla_theme/assets/img/icons/email.svg" alt="" width="25" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if "asset"|app_installed and not 'asset_request_approve' in charts %}
|
||||
{% if perms.asset.change_assetrequest or request.user|is_reportingmanager %}
|
||||
<div class="xl:col-span-4 md:col-span-12 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Asset Requests To Approve" %}</h3>
|
||||
{% if perms.asset.change_assetrequest or request.user|is_reportingmanager %}
|
||||
<div class="xl:col-span-7 md:col-span-8 col-span-12 bg-white p-6 rounded-md shadow-card" >
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Asset Requests To Approve" %}</h3>
|
||||
</div>
|
||||
<div class="flex flex-col items-center justify-center" hx-get='{% url "dashboard-asset-request-approve" %}' hx-trigger="load">
|
||||
{% comment %} <img src="/static/horilla_theme/assets/img/no-records.svg" alt="" width="300" class="mb-4" />
|
||||
<p class="text-[#666]">No records available at the moment</p> {% endcomment %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-center justify-center h-full" hx-get='{% url "dashboard-asset-request-approve" %}' hx-trigger="load">
|
||||
{% comment %} <img src="/static/horilla_theme/assets/img/no-records.svg" alt="" width="300" class="mb-4" />
|
||||
<p class="text-[#666]">No records available at the moment</p> {% endcomment %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<div class="xl:col-span-5 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">Overtime TO Approve</h3>
|
||||
|
||||
{% if "attendance"|app_installed %}
|
||||
{% if perms.employee.view_employee or request.user|is_reportingmanager %}
|
||||
{% if not 'online_employees' in charts %}
|
||||
<div class="xl:col-span-4 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Online Employees" %}</h3>
|
||||
</div>
|
||||
<div class="flex-col items-center justify-center h-[400px]" hx-get="{% url 'not-out-yet' %}" hx-trigger="load">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if not 'offline_employees' in charts %}
|
||||
<div class="xl:col-span-5 md:col-span-7 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Offline Employees" %}</h3>
|
||||
</div>
|
||||
<div class="flex-col items-center justify-center" hx-get="{% url 'not-in-yet' %}" hx-trigger="load">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if not 'overtime_approve' in charts %}
|
||||
<div class="xl:col-span-5 md:col-span-7 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Overtime To Approve" %}</h3>
|
||||
</div>
|
||||
<div class="flex-col items-center justify-center" hx-get="{% url 'dashboard-overtime-approve' %}" hx-trigger="load">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<div class="xl:col-span-4 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-md font-semibold">
|
||||
{% trans "Attendance Analytic" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="overflow-hidden overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<th class="text-sm font-medium text-left p-3 pl-0">
|
||||
<span class="flex w-max">Employee</span>
|
||||
</th>
|
||||
<th class="text-sm font-medium text-left p-3 pl-0">
|
||||
<span class="flex w-max">Overtime</span>
|
||||
</th>
|
||||
<th class="text-sm font-medium text-left p-3 pl-0">
|
||||
<span class="flex w-max">Action</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
10:45
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-1">
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#07bd072e] text-[#00c700] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</button>
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#ff000024] text-[red] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
10:45
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-1">
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#07bd072e] text-[#00c700] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</button>
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#ff000024] text-[red] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
10:45
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-1">
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#07bd072e] text-[#00c700] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</button>
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#ff000024] text-[red] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
10:45
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-1">
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#07bd072e] text-[#00c700] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</button>
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#ff000024] text-[red] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
10:45
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-1">
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#07bd072e] text-[#00c700] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</button>
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#ff000024] text-[red] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-[#ececec]">
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-3 items-center w-max">
|
||||
<img src="/static/horilla_theme/assets/icons/user1.png" alt="" width="30" /><span>Richard Dom</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
10:45
|
||||
</td>
|
||||
<td class="text-sm text-left p-3 pl-0 text-[#666]">
|
||||
<div class="flex gap-1">
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#07bd072e] text-[#00c700] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</button>
|
||||
<button class="cursor-pointer px-2 py-1 text-xs bg-[#ff000024] text-[red] rounded-sm w-6 h-6 flex items-center justify-center">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="flex gap-2 justify-between items-center mb-4">
|
||||
<select id="type" class="oh-select" name="type" onchange="changeView(this)" style="
|
||||
width: 150px;
|
||||
padding: 5px;
|
||||
color: #5e5c5c;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d1d5db;
|
||||
">
|
||||
<option value="day">{% trans "Day" %}</option>
|
||||
<option value="weekly">{% trans "Weekly" %}</option>
|
||||
<option value="monthly">{% trans "Monthly" %}</option>
|
||||
<option value="date_range">{% trans "Date range" %}</option>
|
||||
</select>
|
||||
<input type="date" id="attendance_month" onchange="changeMonth()" class="oh-select" style="
|
||||
width: 150px;
|
||||
padding: 5px;
|
||||
color: #5e5c5c;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d1d5db;
|
||||
" />
|
||||
</div>
|
||||
<div class="w-full max-w-xs mx-auto">
|
||||
<div class="relative">
|
||||
<canvas id="dailyAnalytic"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="xl:col-span-4 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Hours Chart" %}</h3>
|
||||
<input type="month" class="mb-2 float-end pointer oh-select"
|
||||
id="hourAccountMonth" onchange="dynamicMonth($(this))"
|
||||
style="
|
||||
width: 150px;
|
||||
padding: 5px;
|
||||
color: #5e5c5c;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d1d5db;
|
||||
" />
|
||||
</div>
|
||||
<div class="w-full max-w-xs mx-auto">
|
||||
<div class="relative">
|
||||
<canvas id="pendingHoursCanvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if "leave"|app_installed and not 'overall_leave_chart' in charts %}
|
||||
{% if perms.leave.view_leaverequest %}
|
||||
<div class="xl:col-span-3 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Overall Leave" %}</h3>
|
||||
<select class="oh-select oh-select--sm float-end w-[110px]" name="" id="overAllLeaveSelect" >
|
||||
<option value="today" selected>{% trans "Today" %}</option>
|
||||
<option value="week">{% trans "This Week" %}</option>
|
||||
<option value="month">{% trans "This Month" %}</option>
|
||||
<option value="year">{% trans "This Year" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-full max-w-xs mx-auto">
|
||||
<div class="relative">
|
||||
<canvas id="overAllLeave"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if "leave"|app_installed %}
|
||||
{% if not 'leave_request_approve' in charts %}
|
||||
{% if perms.leave.change_leaverequest or request.user|is_reportingmanager %}
|
||||
<div class="xl:col-span-5 md:col-span-7 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Leave Requests To Approve" %}</h3>
|
||||
</div>
|
||||
<div class="flex-col items-center justify-center" hx-get="{% url 'leave-request-and-approve' %}" hx-trigger="load">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if not 'leave_allocation_approve' in charts %}
|
||||
{% if perms.leave.change_leaveallocationrequest or request.user|is_reportingmanager %}
|
||||
<div class="xl:col-span-6 md:col-span-8 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Leave Allocation Request To Approve" %}</h3>
|
||||
</div>
|
||||
<div class="flex-col items-center justify-center" hx-get="{% url 'leave-allocation-approve' %}" hx-trigger="load">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif%}
|
||||
|
||||
<div class="xl:col-span-3 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Employees Chart" %}</h3>
|
||||
</div>
|
||||
<div class="w-full max-w-xs mx-auto">
|
||||
<div class="relative">
|
||||
<canvas id="totalEmployees"></canvas>
|
||||
</div>
|
||||
<div id="employeeChartLegend" class="mt-4 flex justify-center flex-wrap gap-3 text-xs"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if "pms"|app_installed %}
|
||||
{% if not 'feedback_answer' in charts %}
|
||||
<div class="xl:col-span-6 md:col-span-8 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Feedback To Answers" %}</h3>
|
||||
</div>
|
||||
<div class="flex-col items-center justify-center" hx-get="{% url 'dashboard-feedback-answer' %}" hx-trigger="load">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if not 'feedback_status' in charts %}
|
||||
{% if perms.pms.view_feedback or request.user|is_reportingmanager %}
|
||||
<div class="xl:col-span-3 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Feedback Status" %}</h3>
|
||||
</div>
|
||||
<div class="w-full max-w-xs mx-auto">
|
||||
<div class="relative">
|
||||
<canvas id="feedbackChart"></canvas>
|
||||
</div>
|
||||
<div id="feedbackChartLegend" class="mt-4 flex justify-center flex-wrap gap-3 text-xs"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if not 'objective_status' in charts %}
|
||||
<div class="xl:col-span-3 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="text-md font-semibold">{% trans "Objective Status" %}</h3>
|
||||
</div>
|
||||
<div class="w-full max-w-xs mx-auto">
|
||||
<div class="relative">
|
||||
<canvas id="objectiveChart"></canvas>
|
||||
</div>
|
||||
<div id="feedbackChartLegend" class="mt-4 flex justify-center flex-wrap gap-3 text-xs"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<script src="{% static 'dashboard/employeeChart.js' %}"></script>
|
||||
@@ -545,3 +490,14 @@
|
||||
<!-- onboarding dashboard -->
|
||||
<script src="{% static 'dashboard/onboardChart.js' %}"></script>
|
||||
{% endif %}
|
||||
|
||||
{% if "attendance"|app_installed %}
|
||||
{% if perms.attendance.view_attendance or request.user|is_reportingmanager %}
|
||||
<script src="{% static 'dashboard/attendanceChart.js' %}"></script>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if "leave"|app_installed %}
|
||||
<script src="{% static 'dashboard/onLeave.js' %}"></script>
|
||||
<script src="{% static 'dashboard/leaveChart.js' %}"></script>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,67 +1,168 @@
|
||||
$(document).ready(function () {
|
||||
//Todays leave count department wise chart
|
||||
if (document.getElementById("overAllLeave")){
|
||||
var myChart1 = document.getElementById("overAllLeave").getContext("2d");
|
||||
var overAllLeave = new Chart(myChart1, {
|
||||
let overAllLeaveChart = null;
|
||||
|
||||
function renderOverAllLeaveChart(data, labels) {
|
||||
const ctx = document.getElementById("overAllLeave")?.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
const dataset = [{
|
||||
label: "Leave count",
|
||||
data: data,
|
||||
backgroundColor: ["#cfe9ff", "#ffc9de", "#e6ccff"], // Customize as needed
|
||||
borderWidth: 0,
|
||||
}];
|
||||
|
||||
if (overAllLeaveChart) {
|
||||
overAllLeaveChart.data.labels = labels;
|
||||
overAllLeaveChart.data.datasets = dataset;
|
||||
overAllLeaveChart.update();
|
||||
return;
|
||||
}
|
||||
|
||||
overAllLeaveChart = new Chart(ctx, {
|
||||
type: "doughnut",
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "Leave count",
|
||||
data: [],
|
||||
backgroundColor: null,
|
||||
},
|
||||
],
|
||||
labels: labels,
|
||||
datasets: dataset,
|
||||
},
|
||||
options: {
|
||||
cutout: "70%",
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
onClick: (e, activeEls) => {
|
||||
let datasetIndex = activeEls[0].datasetIndex;
|
||||
let dataIndex = activeEls[0].index;
|
||||
let datasetLabel = e.chart.data.datasets[datasetIndex].label;
|
||||
let value = e.chart.data.datasets[datasetIndex].data[dataIndex];
|
||||
let label = e.chart.data.labels[dataIndex];
|
||||
params =`?department_name=${label}&overall_leave=${$("#overAllLeaveSelect").val()}`;
|
||||
window.location.href = "/leave/request-view" + params;
|
||||
if (activeEls.length > 0) {
|
||||
const datasetIndex = activeEls[0].datasetIndex;
|
||||
const dataIndex = activeEls[0].index;
|
||||
const label = e.chart.data.labels[dataIndex];
|
||||
const selected = $("#overAllLeaveSelect").val();
|
||||
const params = `?department_name=${label}&overall_leave=${selected}`;
|
||||
window.location.href = "/leave/request-view" + params;
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
position: "bottom",
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
pointStyle: "circle",
|
||||
padding: 20,
|
||||
font: {
|
||||
size: 12,
|
||||
},
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
padding: 10,
|
||||
cornerRadius: 4,
|
||||
backgroundColor: "#333",
|
||||
titleColor: "#fff",
|
||||
bodyColor: "#fff",
|
||||
callbacks: {
|
||||
label: function (context) {
|
||||
return context.parsed;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
afterRender: (chart) => emptyChart(chart),
|
||||
afterRender: (chart) => {
|
||||
if (typeof emptyChart === "function") {
|
||||
emptyChart(chart);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/leave/overall-leave?overall_leave=today",
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
if (overAllLeave){
|
||||
overAllLeave.data.labels = response.labels;
|
||||
overAllLeave.data.datasets[0].data = response.data;
|
||||
overAllLeave.data.datasets[0].backgroundColor = null;
|
||||
overAllLeave.update();
|
||||
}
|
||||
},
|
||||
});
|
||||
$(document).on("change", "#overAllLeaveSelect", function () {
|
||||
var selected = $(this).val();
|
||||
function fetchOverAllLeaveData(overallLeaveType = "today") {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: `/leave/overall-leave?overall_leave=${selected}`,
|
||||
url: `/leave/overall-leave?overall_leave=${overallLeaveType}`,
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
overAllLeave.data.labels = response.labels;
|
||||
overAllLeave.data.datasets[0].data = response.data;
|
||||
overAllLeave.data.datasets[0].backgroundColor = null;
|
||||
overAllLeave.update();
|
||||
renderOverAllLeaveChart(response.data, response.labels);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//Today leave employees chart
|
||||
// Initial chart load
|
||||
fetchOverAllLeaveData();
|
||||
|
||||
// Dropdown change event
|
||||
$(document).on("change", "#overAllLeaveSelect", function () {
|
||||
fetchOverAllLeaveData($(this).val());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// $(document).ready(function () {
|
||||
// //Todays leave count department wise chart
|
||||
// if (document.getElementById("overAllLeave")){
|
||||
// var myChart1 = document.getElementById("overAllLeave").getContext("2d");
|
||||
// var overAllLeave = new Chart(myChart1, {
|
||||
// type: "doughnut",
|
||||
// data: {
|
||||
// labels: [],
|
||||
// datasets: [
|
||||
// {
|
||||
// label: "Leave count",
|
||||
// data: [],
|
||||
// backgroundColor: null,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// options: {
|
||||
// responsive: true,
|
||||
// maintainAspectRatio: false,
|
||||
// onClick: (e, activeEls) => {
|
||||
// let datasetIndex = activeEls[0].datasetIndex;
|
||||
// let dataIndex = activeEls[0].index;
|
||||
// let datasetLabel = e.chart.data.datasets[datasetIndex].label;
|
||||
// let value = e.chart.data.datasets[datasetIndex].data[dataIndex];
|
||||
// let label = e.chart.data.labels[dataIndex];
|
||||
// params =`?department_name=${label}&overall_leave=${$("#overAllLeaveSelect").val()}`;
|
||||
// window.location.href = "/leave/request-view" + params;
|
||||
// },
|
||||
// },
|
||||
// plugins: [
|
||||
// {
|
||||
// afterRender: (chart) => emptyChart(chart),
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// }
|
||||
|
||||
// $.ajax({
|
||||
// type: "GET",
|
||||
// url: "/leave/overall-leave?overall_leave=today",
|
||||
// dataType: "json",
|
||||
// success: function (response) {
|
||||
// if (overAllLeave){
|
||||
// overAllLeave.data.labels = response.labels;
|
||||
// overAllLeave.data.datasets[0].data = response.data;
|
||||
// overAllLeave.data.datasets[0].backgroundColor = null;
|
||||
// overAllLeave.update();
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
// $(document).on("change", "#overAllLeaveSelect", function () {
|
||||
// var selected = $(this).val();
|
||||
// $.ajax({
|
||||
// type: "GET",
|
||||
// url: `/leave/overall-leave?overall_leave=${selected}`,
|
||||
// dataType: "json",
|
||||
// success: function (response) {
|
||||
// overAllLeave.data.labels = response.labels;
|
||||
// overAllLeave.data.datasets[0].data = response.data;
|
||||
// overAllLeave.data.datasets[0].backgroundColor = null;
|
||||
// overAllLeave.update();
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// //Today leave employees chart
|
||||
// });
|
||||
|
||||
@@ -1,99 +1,215 @@
|
||||
$(document).ready(function() {
|
||||
const objectiveChart = document.getElementById("objectiveChart");
|
||||
// data dictionary
|
||||
var objectiveStatusData = {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "objective",
|
||||
data: [],
|
||||
backgroundColor: ["#8de5b3", "#f0a8a6", "#8ed1f7", "#f8e08e", "#c2c7cc"],
|
||||
hoverOffset: 3,
|
||||
},
|
||||
],
|
||||
message:"",
|
||||
};
|
||||
if (document.getElementById("objectiveChart")) {
|
||||
const ctx = document.getElementById("objectiveChart")?.getContext("2d");
|
||||
|
||||
// chart constructor
|
||||
if (objectiveChart != null) {
|
||||
var objectiveStatusChart = new Chart(objectiveChart, {
|
||||
type: "doughnut",
|
||||
data: objectiveStatusData,
|
||||
options: {
|
||||
let objectiveChartInstance = null;
|
||||
|
||||
|
||||
function renderObjectiveChart(dataSet, labels) {
|
||||
const updatedDataSet = dataSet.map((ds) => ({
|
||||
...ds,
|
||||
backgroundColor: ["#f8e08e", "#c2c7cc","#8de5b3", "#f0a8a6", "#8ed1f7"],
|
||||
borderWidth: 0,
|
||||
}));
|
||||
|
||||
if (objectiveChartInstance) {
|
||||
objectiveChartInstance.destroy();
|
||||
}
|
||||
|
||||
objectiveChartInstance = new Chart(ctx, {
|
||||
type: "doughnut",
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: updatedDataSet,
|
||||
},
|
||||
options: {
|
||||
cutout: "70%",
|
||||
responsive: true,
|
||||
maintainAspectRatio:false,
|
||||
maintainAspectRatio: false,
|
||||
onClick: (e, activeEls) => {
|
||||
let datasetIndex = activeEls[0].datasetIndex;
|
||||
let dataIndex = activeEls[0].index;
|
||||
let datasetLabel = e.chart.data.datasets[datasetIndex].label;
|
||||
let value = e.chart.data.datasets[datasetIndex].data[dataIndex];
|
||||
let label = e.chart.data.labels[dataIndex];
|
||||
let params = "?status=" + label + "&archive=false" + "&dashboard=True";
|
||||
if (!activeEls.length) return;
|
||||
|
||||
const dataIndex = activeEls[0].index;
|
||||
const label = labels[dataIndex];
|
||||
const params = `?status=${label}&archive=false&dashboard=True`;
|
||||
|
||||
$.ajax({
|
||||
url: "/pms/objective-dashboard-view" + params,
|
||||
type: "GET",
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
},
|
||||
success: (response) => {
|
||||
$("#dashboard").html(response);
|
||||
},
|
||||
error: (error) => {
|
||||
console.log("Error", error);
|
||||
},
|
||||
url: "/pms/objective-dashboard-view" + params,
|
||||
type: "GET",
|
||||
headers: { "X-Requested-With": "XMLHttpRequest" },
|
||||
success: (response) => {
|
||||
$("#dashboard").html(response);
|
||||
$("#back_button").removeClass("d-none");
|
||||
},
|
||||
error: (error) => {
|
||||
console.error("Error loading dashboard:", error);
|
||||
},
|
||||
});
|
||||
$("#back_button").removeClass("d-none");
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
position: "bottom",
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
pointStyle: "circle",
|
||||
padding: 20,
|
||||
font: { size: 12 },
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
padding: 10,
|
||||
cornerRadius: 4,
|
||||
backgroundColor: "#333",
|
||||
titleColor: "#fff",
|
||||
bodyColor: "#fff",
|
||||
callbacks: {
|
||||
label: function (context) {
|
||||
return context.parsed;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
afterRender: (chart) => {
|
||||
if (typeof emptyChart === "function") {
|
||||
emptyChart(chart);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
// Update chart data and redraw
|
||||
function updateObjectiveChart(data) {
|
||||
const dataset = [{
|
||||
label: "Objective",
|
||||
data: data.objective_value,
|
||||
}];
|
||||
renderObjectiveChart(dataset, data.objective_label);
|
||||
}
|
||||
|
||||
// Initial fetch
|
||||
$.ajax({
|
||||
url: "/pms/dashboard-objective-status",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
headers: { "X-Requested-With": "XMLHttpRequest" },
|
||||
success: (response) => {
|
||||
updateObjectiveChart(response);
|
||||
},
|
||||
plugins: [{
|
||||
afterRender: (chart)=>emptyChart(chart)
|
||||
}],
|
||||
});
|
||||
}
|
||||
error: (error) => {
|
||||
console.error("Error loading objective chart data:", error);
|
||||
},
|
||||
});
|
||||
|
||||
function objectiveStatusDataUpdate(data) {
|
||||
objectiveStatusData.labels = data.objective_label;
|
||||
objectiveStatusData.datasets[0].data = data.objective_value;
|
||||
objectiveStatusData.message = data.message;
|
||||
if (objectiveStatusChart){
|
||||
objectiveStatusChart.update();
|
||||
// Optional chart type toggle (pie/bar/doughnut etc.)
|
||||
$("#objective-status-chart").click(function () {
|
||||
const types = ["bar", "doughnut", "pie", "line"];
|
||||
const current = types.indexOf(objectiveChartInstance.config.type);
|
||||
const nextType = types[(current + 1) % types.length];
|
||||
objectiveChartInstance.config.type = nextType;
|
||||
objectiveChartInstance.update();
|
||||
});
|
||||
}
|
||||
}
|
||||
// const objectiveChart = document.getElementById("objectiveChart");
|
||||
// // data dictionary
|
||||
// var objectiveStatusData = {
|
||||
// labels: [],
|
||||
// datasets: [
|
||||
// {
|
||||
// label: "objective",
|
||||
// data: [],
|
||||
// backgroundColor: ["#8de5b3", "#f0a8a6", "#8ed1f7", "#f8e08e", "#c2c7cc"],
|
||||
// hoverOffset: 3,
|
||||
// },
|
||||
// ],
|
||||
// message:"",
|
||||
// };
|
||||
|
||||
$.ajax({
|
||||
url: "/pms/dashboard-objective-status",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
},
|
||||
success: (response) => {
|
||||
objectiveStatusDataUpdate(response);
|
||||
},
|
||||
error: (error) => {
|
||||
console.log("Error", error);
|
||||
},
|
||||
});
|
||||
// // chart constructor
|
||||
// if (objectiveChart != null) {
|
||||
// var objectiveStatusChart = new Chart(objectiveChart, {
|
||||
// type: "doughnut",
|
||||
// data: objectiveStatusData,
|
||||
// options: {
|
||||
// responsive: true,
|
||||
// maintainAspectRatio:false,
|
||||
// onClick: (e, activeEls) => {
|
||||
// let datasetIndex = activeEls[0].datasetIndex;
|
||||
// let dataIndex = activeEls[0].index;
|
||||
// let datasetLabel = e.chart.data.datasets[datasetIndex].label;
|
||||
// let value = e.chart.data.datasets[datasetIndex].data[dataIndex];
|
||||
// let label = e.chart.data.labels[dataIndex];
|
||||
// let params = "?status=" + label + "&archive=false" + "&dashboard=True";
|
||||
|
||||
// chart change
|
||||
$("#objective-status-chart").click(function (e) {
|
||||
var chartType = objectiveStatusChart.config.type;
|
||||
if (chartType === "line") {
|
||||
chartType = "bar";
|
||||
} else if (chartType === "bar") {
|
||||
chartType = "doughnut";
|
||||
} else if (chartType === "doughnut") {
|
||||
chartType = "pie";
|
||||
} else if (chartType === "pie") {
|
||||
chartType = "line";
|
||||
}
|
||||
objectiveStatusChart.config.type = chartType;
|
||||
if (objectiveStatusChart){
|
||||
objectiveStatusChart.update();
|
||||
}
|
||||
// $.ajax({
|
||||
// url: "/pms/objective-dashboard-view" + params,
|
||||
// type: "GET",
|
||||
// headers: {
|
||||
// "X-Requested-With": "XMLHttpRequest",
|
||||
// },
|
||||
// success: (response) => {
|
||||
// $("#dashboard").html(response);
|
||||
// },
|
||||
// error: (error) => {
|
||||
// console.log("Error", error);
|
||||
// },
|
||||
// });
|
||||
// $("#back_button").removeClass("d-none");
|
||||
// },
|
||||
// },
|
||||
// plugins: [{
|
||||
// afterRender: (chart)=>emptyChart(chart)
|
||||
// }],
|
||||
// });
|
||||
// }
|
||||
|
||||
});
|
||||
// function objectiveStatusDataUpdate(data) {
|
||||
// objectiveStatusData.labels = data.objective_label;
|
||||
// objectiveStatusData.datasets[0].data = data.objective_value;
|
||||
// objectiveStatusData.message = data.message;
|
||||
// if (objectiveStatusChart){
|
||||
// objectiveStatusChart.update();
|
||||
// }
|
||||
// }
|
||||
|
||||
// $.ajax({
|
||||
// url: "/pms/dashboard-objective-status",
|
||||
// type: "GET",
|
||||
// dataType: "json",
|
||||
// headers: {
|
||||
// "X-Requested-With": "XMLHttpRequest",
|
||||
// },
|
||||
// success: (response) => {
|
||||
// objectiveStatusDataUpdate(response);
|
||||
// },
|
||||
// error: (error) => {
|
||||
// console.log("Error", error);
|
||||
// },
|
||||
// });
|
||||
|
||||
// // chart change
|
||||
// $("#objective-status-chart").click(function (e) {
|
||||
// var chartType = objectiveStatusChart.config.type;
|
||||
// if (chartType === "line") {
|
||||
// chartType = "bar";
|
||||
// } else if (chartType === "bar") {
|
||||
// chartType = "doughnut";
|
||||
// } else if (chartType === "doughnut") {
|
||||
// chartType = "pie";
|
||||
// } else if (chartType === "pie") {
|
||||
// chartType = "line";
|
||||
// }
|
||||
// objectiveStatusChart.config.type = chartType;
|
||||
// if (objectiveStatusChart){
|
||||
// objectiveStatusChart.update();
|
||||
// }
|
||||
|
||||
// });
|
||||
|
||||
// objecitve chart section end
|
||||
|
||||
@@ -281,85 +397,221 @@ $("#key-result-status-chart").click(() => {
|
||||
|
||||
// key result chart section
|
||||
|
||||
const feedbackStatusChartCtx = document.getElementById("feedbackChart");
|
||||
// const feedbackStatusChartCtx = document.getElementById("feedbackChart");
|
||||
|
||||
// data dictionary
|
||||
var feedbackStatusData = {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "Feedback",
|
||||
data: [],
|
||||
backgroundColor: ["#8de5b3", "#f0a8a6", "#8ed1f7", "#f8e08e", "#c2c7cc"],
|
||||
hoverOffset: 3,
|
||||
// // data dictionary
|
||||
// var feedbackStatusData = {
|
||||
// labels: [],
|
||||
// datasets: [
|
||||
// {
|
||||
// label: "Feedback",
|
||||
// data: [],
|
||||
// backgroundColor: ["#8de5b3", "#f0a8a6", "#8ed1f7", "#f8e08e", "#c2c7cc"],
|
||||
// hoverOffset: 3,
|
||||
// },
|
||||
// ],
|
||||
// message:"",
|
||||
// };
|
||||
|
||||
// // chart constructor
|
||||
// if (feedbackStatusChartCtx != null) {
|
||||
// var feedbackStatusChart = new Chart(feedbackStatusChartCtx, {
|
||||
// type: "pie",
|
||||
// data: feedbackStatusData,
|
||||
// options: {
|
||||
// responsive: true,
|
||||
// maintainAspectRatio:false,
|
||||
// onClick: (e, activeEls) => {
|
||||
// let datasetIndex = activeEls[0].datasetIndex;
|
||||
// let dataIndex = activeEls[0].index;
|
||||
// let datasetLabel = e.chart.data.datasets[datasetIndex].label;
|
||||
// let value = e.chart.data.datasets[datasetIndex].data[dataIndex];
|
||||
// let label = e.chart.data.labels[dataIndex];
|
||||
// let params = "?status=" + label + "&archive=false";
|
||||
// window.location.href = "/pms/feedback-view" + params;
|
||||
// },
|
||||
// },
|
||||
// plugins: [{
|
||||
// afterRender: (chart)=>emptyChart(chart)
|
||||
// }],
|
||||
// });
|
||||
// }
|
||||
|
||||
// function feedbackStatusDataUpdate(data) {
|
||||
// feedbackStatusData.labels = data.feedback_label;
|
||||
// feedbackStatusData.datasets[0].data = data.feedback_value;
|
||||
// feedbackStatusData.message = data.message;
|
||||
// if (feedbackStatusChart){
|
||||
// feedbackStatusChart.update();
|
||||
// }
|
||||
// }
|
||||
|
||||
// $.ajax({
|
||||
// url: "/pms/dashboard-feedback-status",
|
||||
// type: "GET",
|
||||
// dataType: "json",
|
||||
// headers: {
|
||||
// "X-Requested-With": "XMLHttpRequest",
|
||||
// },
|
||||
// success: (response) => {
|
||||
// feedbackStatusDataUpdate(response);
|
||||
// },
|
||||
// error: (error) => {
|
||||
// console.log("Error", error);
|
||||
// },
|
||||
// });
|
||||
|
||||
// // chart change
|
||||
// $("#feedback-status-chart").click(function (e) {
|
||||
// var chartType = feedbackStatusChart.config.type;
|
||||
// if (chartType === "line") {
|
||||
// chartType = "bar";
|
||||
// } else if (chartType === "bar") {
|
||||
// chartType = "doughnut";
|
||||
// } else if (chartType === "doughnut") {
|
||||
// chartType = "pie";
|
||||
// } else if (chartType === "pie") {
|
||||
// chartType = "line";
|
||||
// }
|
||||
// feedbackStatusChart.config.type = chartType;
|
||||
// if (feedbackStatusChart){
|
||||
// feedbackStatusChart.update();
|
||||
// }
|
||||
// });
|
||||
|
||||
if (document.getElementById("feedbackChart")) {
|
||||
const ctx = document.getElementById("feedbackChart")?.getContext("2d");
|
||||
let feedbackChartInstance = null;
|
||||
let visibility = [];
|
||||
|
||||
function renderFeedbackChart(dataSet, labels) {
|
||||
const values = dataSet[0].data;
|
||||
const colors = [
|
||||
"#93c5fd",
|
||||
"#facc15",
|
||||
"#f87171",
|
||||
"#ddd6fe",
|
||||
"#a5b4fc",
|
||||
"#d1d5db",
|
||||
];
|
||||
visibility = Array(labels.length).fill(true);
|
||||
|
||||
// Destroy previous chart if it exists
|
||||
if (feedbackChartInstance) {
|
||||
feedbackChartInstance.destroy();
|
||||
}
|
||||
|
||||
feedbackChartInstance = new Chart(ctx, {
|
||||
type: "doughnut",
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [
|
||||
{
|
||||
...dataSet[0],
|
||||
backgroundColor: colors.slice(0, labels.length),
|
||||
borderWidth: 0,
|
||||
borderRadius: 10,
|
||||
hoverOffset: 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
message:"",
|
||||
};
|
||||
|
||||
// chart constructor
|
||||
if (feedbackStatusChartCtx != null) {
|
||||
var feedbackStatusChart = new Chart(feedbackStatusChartCtx, {
|
||||
type: "pie",
|
||||
data: feedbackStatusData,
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio:false,
|
||||
onClick: (e, activeEls) => {
|
||||
let datasetIndex = activeEls[0].datasetIndex;
|
||||
let dataIndex = activeEls[0].index;
|
||||
let datasetLabel = e.chart.data.datasets[datasetIndex].label;
|
||||
let value = e.chart.data.datasets[datasetIndex].data[dataIndex];
|
||||
let label = e.chart.data.labels[dataIndex];
|
||||
let params = "?status=" + label + "&archive=false";
|
||||
window.location.href = "/pms/feedback-view" + params;
|
||||
cutout: "70%",
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
onClick: function (e, activeEls) {
|
||||
if (!activeEls.length) return;
|
||||
|
||||
const dataIndex = activeEls[0].index;
|
||||
const label = labels[dataIndex];
|
||||
const params = "?status=" + label + "&archive=false";
|
||||
window.location.href = "/pms/feedback-view" + params;
|
||||
},
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
tooltip: {
|
||||
backgroundColor: "#111827",
|
||||
bodyColor: "#f3f4f6",
|
||||
borderColor: "#e5e7eb",
|
||||
borderWidth: 1,
|
||||
},
|
||||
},
|
||||
plugins: [{
|
||||
afterRender: (chart)=>emptyChart(chart)
|
||||
}],
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
afterRender: (chart) => {
|
||||
if (typeof emptyChart === "function") {
|
||||
emptyChart(chart);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function feedbackStatusDataUpdate(data) {
|
||||
feedbackStatusData.labels = data.feedback_label;
|
||||
feedbackStatusData.datasets[0].data = data.feedback_value;
|
||||
feedbackStatusData.message = data.message;
|
||||
if (feedbackStatusChart){
|
||||
feedbackStatusChart.update();
|
||||
// 🧩 Custom Legend Generation
|
||||
const $legendContainer = $("#feedbackChartLegend");
|
||||
$legendContainer.empty();
|
||||
|
||||
labels.forEach((label, index) => {
|
||||
const color = colors[index % colors.length];
|
||||
|
||||
const $item = $(`
|
||||
<div style="display: flex; align-items: center; margin-bottom: 6px; cursor: pointer;">
|
||||
<span style="display: inline-block; width: 12px; height: 12px; border-radius: 50%; background-color: ${color}; margin-right: 8px;"></span>
|
||||
<span class="legend-label">${label}</span>
|
||||
</div>
|
||||
`);
|
||||
|
||||
$legendContainer.append($item);
|
||||
|
||||
$item.on("click", function () {
|
||||
visibility[index] = !visibility[index];
|
||||
|
||||
feedbackChartInstance.data.datasets[0].data = values.map((val, i) =>
|
||||
visibility[i] ? val : 0
|
||||
);
|
||||
|
||||
const $dot = $(this).find("span").first();
|
||||
const $label = $(this).find(".legend-label");
|
||||
|
||||
if (visibility[index]) {
|
||||
$dot.css("opacity", "1");
|
||||
$label.css("text-decoration", "none");
|
||||
} else {
|
||||
$dot.css("opacity", "0.4");
|
||||
$label.css("text-decoration", "line-through");
|
||||
}
|
||||
|
||||
feedbackChartInstance.update();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "/pms/dashboard-feedback-status",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
// 🔄 Load data via AJAX
|
||||
function fetchFeedbackData() {
|
||||
$.ajax({
|
||||
url: "/pms/dashboard-feedback-status",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
},
|
||||
success: (response) => {
|
||||
feedbackStatusDataUpdate(response);
|
||||
},
|
||||
error: (error) => {
|
||||
console.log("Error", error);
|
||||
},
|
||||
});
|
||||
},
|
||||
success: function (response) {
|
||||
const dataset = [
|
||||
{
|
||||
label: "Feedback",
|
||||
data: response.feedback_value,
|
||||
},
|
||||
];
|
||||
renderFeedbackChart(dataset, response.feedback_label);
|
||||
},
|
||||
error: function (error) {
|
||||
console.error("Error loading feedback chart:", error);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
fetchFeedbackData();
|
||||
}
|
||||
|
||||
// chart change
|
||||
$("#feedback-status-chart").click(function (e) {
|
||||
var chartType = feedbackStatusChart.config.type;
|
||||
if (chartType === "line") {
|
||||
chartType = "bar";
|
||||
} else if (chartType === "bar") {
|
||||
chartType = "doughnut";
|
||||
} else if (chartType === "doughnut") {
|
||||
chartType = "pie";
|
||||
} else if (chartType === "pie") {
|
||||
chartType = "line";
|
||||
}
|
||||
feedbackStatusChart.config.type = chartType;
|
||||
if (feedbackStatusChart){
|
||||
feedbackStatusChart.update();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user