1364 lines
75 KiB
HTML
Executable File
1364 lines
75 KiB
HTML
Executable File
{% load static basefilters horillafilters employee_filter i18n %} {% load tz %} {% now "Y-m-d" as current_date %}
|
|
{% include 'generic/components.html' %}
|
|
{% load accessibility_filters %}
|
|
<link href="https://fonts.googleapis.com/css2?family=Lobster&display=swap" rel="stylesheet">
|
|
|
|
<div id="mainNav"></div>
|
|
<!-- End of Navigation -->
|
|
<style>
|
|
.oh-card-dashboard--moveable {
|
|
padding: 0 10px 20px 10px;
|
|
}
|
|
|
|
.oh-card-dashboard:not(.tile) {
|
|
cursor: default;
|
|
min-height: 425px;
|
|
}
|
|
|
|
.oh-dashboard__movable-cards {
|
|
padding-right: 0;
|
|
}
|
|
|
|
.oh-card-dashboard--moveable {
|
|
padding-right: 0;
|
|
padding-bottom: 10px;
|
|
}
|
|
|
|
.progress {
|
|
height: 20px;
|
|
width: 110px;
|
|
background-color: lightgrey;
|
|
border: 2px solid #27C20C;
|
|
border-radius: 5px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-bar {
|
|
height: 100%;
|
|
background-color: #27C20C;
|
|
/* Set your desired progress bar color */
|
|
}
|
|
|
|
.progress-text {
|
|
width: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
.oh-modal_close--custom {
|
|
border: none;
|
|
background: none;
|
|
font-size: 1.5rem;
|
|
opacity: 0.7;
|
|
position: absolute;
|
|
top: 25px;
|
|
right: 15px;
|
|
}
|
|
|
|
.container-heading {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
padding: 10px;
|
|
}
|
|
|
|
.oh-kanban-card__title {
|
|
display: block;
|
|
margin-bottom: 10px;
|
|
padding: 10px;
|
|
border: 1px solid hsl(8deg 77% 56% / 40%);
|
|
border-radius: 18px;
|
|
margin-right: 10px;
|
|
background-color: hsl(24.23deg 100% 58.24% / 52.94%);
|
|
}
|
|
|
|
.announcement_title {
|
|
margin-bottom: 10px;
|
|
padding: 8px;
|
|
margin-right: 10px;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.page-wrapper {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
/* Center the modal */
|
|
width: 80%;
|
|
/* Adjust the width of the modal */
|
|
height: 80%;
|
|
/* Adjust the height of the modal */
|
|
overflow: hidden;
|
|
z-index: 1001;
|
|
background: transparent;
|
|
/* Ensure background is transparent */
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
}
|
|
|
|
.blurred-background {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-size: cover;
|
|
filter: blur(5px);
|
|
opacity: 2;
|
|
/* Adjust opacity level */
|
|
z-index: 1000;
|
|
/* Ensure it's behind the canvas */
|
|
}
|
|
</style>
|
|
|
|
<!-- leave allocation reject modal -->
|
|
<div class="oh-modal" id="rejectModal" role="dialog" aria-labelledby="rejectDialogModal" aria-hidden="true">
|
|
<div class="oh-modal__dialog" id="rejectTarget"></div>
|
|
</div>
|
|
|
|
<!-- end of modal -->
|
|
|
|
<!-- activity view modal for attendance activity col -->
|
|
|
|
<div class="oh-modal" id="activityViewModal" role="dialog" aria-hidden="true" style="z-index:1100;">
|
|
<div class="oh-modal__dialog" style="max-width: 900px;">
|
|
<div class="oh-modal__dialog-header">
|
|
<h3 class="oh-main__titlebar-title fw-bold ">{% trans " Activities" %}</h3>
|
|
<button class="oh-modal__close--custom" aria-label="Close"
|
|
onclick="$(this).parents().closest('.oh-modal--show').toggleClass('oh-modal--show');">
|
|
<ion-icon name="close-outline"></ion-icon>
|
|
</button>
|
|
</div>
|
|
<div class="oh-modal__dialog-body" id="activityViewModalBody" style="overflow-x:auto;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- end of modal -->
|
|
|
|
{% include "generic/components.html" %}
|
|
<div class="oh-wrapper">
|
|
|
|
<!-- back button -->
|
|
<div class="d-none mt-5" id="back_button" style="width: 10%">
|
|
<a href="{% url 'home-page' %}" class="oh-btn oh-btn--secondary oh-btn--shadow ms-3">
|
|
<ion-icon class="me-2 md hydrated" name="arrow-back-outline" role="img"
|
|
aria-label="arrow-back-outline"></ion-icon>{% trans "Back" %}</a>
|
|
</div>
|
|
<!-- end of back button -->
|
|
<div class="oh-dashboard row" id="dashboard" style="padding-bottom: 3.5rem;">
|
|
|
|
|
|
<div class="oh-dashboard__left col-12 col-sm-12 col-md-12 col-lg-9">
|
|
<div class="oh-dashboard__cards row">
|
|
{% if perms.employee.view_employee %}
|
|
{% if "recruitment"|app_installed %}
|
|
<div class="col-12 col-sm-12 col-md-6 col-lg-4">
|
|
<div class="oh-card-dashboard oh-card-dashboard--success tile">
|
|
<a href="{% url 'candidate-view' %}?joining_date={{current_date}}"
|
|
style="text-decoration: none">
|
|
<div class="oh-card-dashboard__header">
|
|
<span class="oh-card-dashboard__title">{% trans "New Joining Today" %}</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<div class="oh-card-dashboard__counts">
|
|
<span class="oh-card-dashboard__count" hx-get="{% url 'joining-today-count' %}" hx-trigger="load">
|
|
<div style="height: 67px;"></div>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-sm-12 col-md-6 col-lg-4">
|
|
<div class="oh-card-dashboard oh-card-dashboard oh-card-dashboard--warning tile">
|
|
<a href="{% url 'candidate-view' %}?scheduled_from={{first_day_of_week}}&scheduled_till={{last_day_of_week}}"
|
|
style="text-decoration: none">
|
|
<div class="oh-card-dashboard__header">
|
|
<span class="oh-card-dashboard__title">{% trans "New Joining This Week" %}</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<div class="oh-card-dashboard__counts">
|
|
<span class="oh-card-dashboard__count" hx-get="{% url 'joining-week-count' %}" hx-trigger="load">
|
|
<div style="height: 67px;"></div>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
<div class="col-12 col-sm-12 col-md-6 col-lg-4">
|
|
<a href="{% url 'employee-view' %}" style="text-decoration: none">
|
|
<div class="oh-card-dashboard oh-card-dashboard--neutral tile">
|
|
<div class="oh-card-dashboard__header">
|
|
<span class="oh-card-dashboard__title">{% trans "Total Strength" %}</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<div class="oh-card-dashboard__counts">
|
|
<span class="oh-card-dashboard__count" hx-get="{% url 'total-employees-count' %}"
|
|
hx-trigger="load">
|
|
<div style="height: 67px;"></div>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
<div class="oh-dashboard__movable-cards row mt-4" id="tileContainer">
|
|
{% if "attendance"|app_installed %}
|
|
{% if not 'offline_employees' in charts %}
|
|
{% if perms.employee.view_employee or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="notInYetId">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent" style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Offline Employees" %}</span>
|
|
<span class="float-end chart_close_button " role="button" data-chart="offline_employees" hx-post="{% url 'dashboard-components-toggle' %}?chart_id=offline_employees" hx-target="#notInYetId" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class=" oh-card-dashboard__body" id="notInYetIdBody" style="height:80%">
|
|
<div class="oh-sticky-table h-100" hx-get="{% url 'not-in-yet' %}" hx-trigger="load" style="border: none;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% comment %} <div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="notInYetId" hx-get="{% url 'not-in-yet' %}" hx-trigger="load">
|
|
{% include "dashboard/not_in_yet.html" %}
|
|
</div> {% endcomment %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if not 'online_employees' in charts %}
|
|
{% if perms.employee.view_employee or request.user|is_reportingmanager %}
|
|
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="notoutYetdd">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent"
|
|
style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Online Employees" %}</span>
|
|
<span class="float-end chart_close_button fs-5" role="button" data-chart="online_employees" hx-post="{% url 'dashboard-components-toggle' %}?chart_id=online_employees" hx-target="#notoutYetdd" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter">close</i>
|
|
</span>
|
|
</div>
|
|
<div class=" oh-card-dashboard__body" id="notoutYetddBody" style="height:80%">
|
|
<div class="oh-sticky-table h-100" hx-get="{% url 'not-out-yet' %}" hx-trigger="load" style="border: none;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% comment %} <div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="notoutYetdd" hx-get="{% url 'not-out-yet' %}" hx-trigger="load">
|
|
{% include "dashboard/not_out_yet.html" %}
|
|
</div> {% endcomment %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "leave"|app_installed and not 'overall_leave_chart' in charts %}
|
|
{% if perms.leave.view_leaverequest %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-4 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable1">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Overall Leave" %}</span>
|
|
<span class="float-end chart_close_button ms-3" role="button"
|
|
data-chart="overall_leave_chart"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=overall_leave_chart"
|
|
hx-target="#movable1" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
<select class="oh-select oh-select--sm float-end" 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="oh-card-dashboard__body">
|
|
<canvas id="overAllLeave" style="cursor: pointer" height='300' width="350"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "recruitment"|app_installed and perms.recruitment.view_candidate or request.user|is_stagemanager %}
|
|
{% if not 'hired_candidates' in charts %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable2">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Hired Candidates" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="hired_candidates"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=hired_candidates"
|
|
hx-target="#movable2" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="hiredCandidate" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% if "onboarding"|app_installed and not 'onboarding_candidates' in charts %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable3">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Candidates Started Onboarding" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="onboarding_candidates"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=onboarding_candidates"
|
|
hx-target="#movable3" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="onboardCandidate" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "recruitment"|app_installed and not 'recruitment_analytics' in charts %}
|
|
{% if request.user|is_stagemanager or perms.recruitment.view_recruitment %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable8">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Recruitment Analytics" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="recruitment_analytics"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=recruitment_analytics"
|
|
hx-target="#movable8" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="recruitmentChart1" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "attendance"|app_installed and not 'attendance_analytic' in charts %}
|
|
{% if request.user|is_reportingmanager or perms.attendance.view_attendance %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable4">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider"
|
|
id="attendance_header">
|
|
<div class="oh-card-dashboard__title mb-2">
|
|
{% trans "Attendance Analytics" %}
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="attendance_analytic"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=attendance_analytic"
|
|
hx-target="#movable4" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<select id="type" class="oh-select" name="type" onchange="changeView(this)"
|
|
style="width: 150px; padding: 3px; color: #5e5c5c">
|
|
<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>
|
|
<span id="day_input">
|
|
<input type="date" class="mb-2 float-end pointer oh-select"
|
|
id="attendance_month" onchange="changeMonth()"
|
|
style="width: 100px; color: #5e5c5c" />
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="dailyAnalytic" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "attendance"|app_installed and not 'hours_chart' in charts %}
|
|
{% if request.user|is_reportingmanager or perms.attendance.view_attendance %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="pendingHours">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider"
|
|
id="pendingHoursHeader">
|
|
<div class="oh-card-dashboard__title mb-2">
|
|
{% trans "Hours Chart" %}
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="hours_chart"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=hours_chart"
|
|
hx-target="#pendingHours" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<input type="month" class="mb-2 float-end pointer oh-select"
|
|
id="hourAccountMonth" onchange="dynamicMonth($(this))"
|
|
style="width: 100px; color: #5e5c5c" />
|
|
</div>
|
|
<div class="oh-card-dashboard__body" style="height:300px">
|
|
<canvas id="pendingHoursCanvas" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if not 'employees_chart' in charts %}
|
|
{% if 'employees_chart'|feature_is_accessible:request or perms.employee.view_employee or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-4 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable5">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Employees Chart" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="employees_chart"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=employees_chart"
|
|
hx-target="#movable5" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="totalEmployees" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if not 'department_chart' in charts %}
|
|
{% if 'department_chart'|feature_is_accessible:request or perms.employee.view_employee or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-4 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable6">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Department Chart" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="department_chart"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=department_chart"
|
|
hx-target="#movable6" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="departmentChart" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% 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="col-12 col-sm-12 col-md-12 col-lg-4 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable7">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Gender Chart" %}</span>
|
|
<span class="float-end chart_close_button " role="button" data-chart="gender_chart"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=gender_chart"
|
|
hx-target="#movable7" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="genderChart" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if not 'objective_status' in charts and "pms"|app_installed %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-4 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable9">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Objective Status" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="objective_status"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=objective_status"
|
|
hx-target="#movable9" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="objectiveChart" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% if "pms"|app_installed and not 'key_result_status' in charts %}
|
|
{% if perms.pms.view_employeekeyresult or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-4 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable10">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Key Result Status" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="key_result_status"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=key_result_status"
|
|
hx-target="#movable10" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="keyResultChart" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "pms"|app_installed and not 'feedback_status' in charts %}
|
|
{% if perms.pms.view_feedback or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-4 oh-card-dashboard--moveable dashboardChart"
|
|
id="movable11">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Feedback Status" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="feedback_status"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=feedback_status"
|
|
hx-target="#movable11" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body">
|
|
<div class="oh-card-dashboard__body">
|
|
<canvas id="feedbackChart" style="cursor: pointer"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if not 'shift_request_approve' in charts %}
|
|
{% if perms.base.change_shiftrequest or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="shiftRequestApprove">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent"
|
|
style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Shift Requests To Approve" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="shift_request_approve"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=shift_request_approve"
|
|
hx-target="#shiftRequestApprove" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class=" oh-card-dashboard__body" id="shiftRequestApproveBody" style="height:80%">
|
|
<div class="oh-sticky-table h-100" hx-get="{% url 'dashboard-shift-request' %}" hx-trigger="load" style="border: none;">
|
|
</div>
|
|
{% comment %} {% include "request_and_approve/shift_request.html" %} {% endcomment %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if not 'work_type_request_approve' in charts %}
|
|
{% if perms.base.change_worktyperequest or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="WorkTypeRequestApprove">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent"
|
|
style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Work Type Requests To Approve" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="work_type_request_approve"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=work_type_request_approve"
|
|
hx-target="#WorkTypeRequestApprove" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
|
|
<div class=" oh-card-dashboard__body" id="WorkTypeRequestApproveBody" style="height:80%">
|
|
<div class="oh-sticky-table h-100" hx-get="{% url 'dashboard-work-type-request' %}" hx-trigger="load" style="border: none;">
|
|
</div>
|
|
{% comment %} {% include "request_and_approve/work_type_request.html" %} {% endcomment %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "attendance"|app_installed and not 'overtime_approve' in charts %}
|
|
{% if perms.attendance.change_attendance or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart" id="OTApprove">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent"
|
|
style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Overtime To Approve" %}</span>
|
|
<span class="float-end chart_close_button " role="button" data-chart="overtime_approve" hx-post="{% url 'dashboard-components-toggle' %}?chart_id=overtime_approve" hx-target="#OTApprove" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
|
|
<div class=" oh-card-dashboard__body" id="OTApproveTarget" style="height:80%">
|
|
<div class="oh-sticky-table h-100" hx-get="{% url 'dashboard-overtime-approve' %}" hx-trigger="load" style="border: none;">
|
|
</div>
|
|
{% comment %} {% include "request_and_approve/overtime_approve.html" %} {% endcomment %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "attendance"|app_installed %}
|
|
<script src="{% static 'cbv/attendance_activity.js' %}"></script>
|
|
|
|
{% if not 'attendance_validate' in charts %}
|
|
{% if perms.attendance.change_attendance or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart" id="AttendanceValidate">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent"
|
|
style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Attendance To Validate" %}</span>
|
|
<span class="float-end chart_close_button " role="button" data-chart="attendance_validate" hx-post="{% url 'dashboard-components-toggle' %}?chart_id=attendance_validate" hx-target="#AttendanceValidate" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
|
|
<div class=" oh-card-dashboard__body" id="AttendanceValidateTarget" style="height:80%">
|
|
<div class="oh-sticky-table h-100" hx-get="{% url 'dashboard-attendance-validate' %}" hx-trigger="load" style="border: none;">
|
|
</div>
|
|
{% comment %} {% include "request_and_approve/attendance_validate.html" %} {% endcomment %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "leave"|app_installed and not 'leave_request_approve' in charts %}
|
|
{% if perms.leave.change_leaverequest or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="LeaveApprove">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent"
|
|
style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Leave Requests To Approve" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="leave_request_approve"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=leave_request_approve"
|
|
hx-target="#LeaveApprove" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body" id="LeaveApproveBody"
|
|
style="height:80%">
|
|
<div class="oh-sticky-table h-100" hx-get='{% url "leave-request-and-approve" %}' hx-trigger="load" style="border: none;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "leave"|app_installed and not 'leave_allocation_approve' in charts %}
|
|
{% if perms.leave.change_leaveallocationrequest or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="LeaveAllocationApprove">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent"
|
|
style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Leave Allocation Request To Approve" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="leave_allocation_approve"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=leave_allocation_approve"
|
|
hx-target="#LeaveAllocationApprove" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
|
|
<div class=" oh-card-dashboard__body" id="LeaveAllocationApproveBody" style="height:80%">
|
|
<div class="oh-sticky-table h-100" hx-get="{% url 'leave-allocation-approve' %}" hx-trigger="load" style="border: none;">
|
|
</div>
|
|
|
|
{% comment %} {% include "request_and_approve/leave_request_approve.html" %} {% endcomment %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if "pms"|app_installed and not 'feedback_answer' in charts %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="feedbackAnswer">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent"
|
|
style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Feedback To Answers" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="feedback_answer"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=feedback_answer"
|
|
hx-target="#feedbackAnswer" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body" id="feedbackAnswerBody"
|
|
hx-get="{% url 'dashboard-feedback-answer' %}" hx-trigger="load" style="height:80%">
|
|
{% comment %} {% include "request_and_approve/feedback_answer.html" %} {% endcomment %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% if "asset"|app_installed and not 'asset_request_approve' in charts %}
|
|
{% if perms.asset.change_assetrequest or request.user|is_reportingmanager %}
|
|
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable dashboardChart"
|
|
id="assetRequestApprove">
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent"
|
|
style="height:425px">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Asset Requests To Approve" %}</span>
|
|
<span class="float-end chart_close_button " role="button"
|
|
data-chart="asset_request_approve"
|
|
hx-post="{% url 'dashboard-components-toggle' %}?chart_id=asset_request_approve"
|
|
hx-target="#assetRequestApprove" hx-swap="outerHTML">
|
|
<i class="material-icons fw-lighter fs-5">close</i>
|
|
</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body" id="assetRequestApproveBody"
|
|
style="height:80%">
|
|
<div class="oh-sticky-table h-100" hx-get='{% url "dashboard-asset-request-approve" %}' hx-trigger="load" style="border: none;">
|
|
</div>
|
|
{% comment %} {% include "request_and_approve/asset_requests_approve.html" %} {% endcomment %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="oh-dashboard__right col-12 col-sm-12 col-md-12 col-lg-3">
|
|
{% if 'birthday_view'|feature_is_accessible:request or perms.employee.view_employee %}
|
|
<div class="oh-dashboard__events" hx-get="{% url 'get-birthday' %}" hx-trigger="load"> </div>
|
|
{% endif %}
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent mb-3">
|
|
<div style="display: flex;align-items:center;justify-content:space-between;margin-right:20px">
|
|
<span class="oh-card-dashboard__title">{% trans "Announcements" %}</span>
|
|
{% if perms.base.add_announcement %}
|
|
<span>
|
|
<button id="addAnnouncement" style="display: inline-block;padding: 0px;
|
|
border-radius: 6px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 50px;
|
|
height: 28px;" class="oh-btn oh-btn--secondary-outline float-end ms-3"
|
|
hx-get="{% url 'create-announcement' %}" hx-target="#objectCreateModalTarget"
|
|
hx-swap="innerHTML" data-toggle="oh-modal-toggle" data-target="#objectCreateModal"
|
|
title="{% trans 'Create Announcement' %}">
|
|
<ion-icon name="add-outline" class="m-0"></ion-icon>
|
|
</button>
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<div class="oh-card-dashboard__body" hx-get="{% url 'announcement-list' %}" hx-trigger="load" id="announcementListCard">
|
|
<div class="animated-background"></div>
|
|
</div>
|
|
</div>
|
|
{% if "leave"|app_installed %}
|
|
{% if perms.leave.view_leaverequest or request.user|is_reportingmanager %}
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent mb-3">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "On Leave" %}</span>
|
|
</div>
|
|
<div class="oh-card-dashboard__body" hx-get="{% url 'employee-leave' %}" hx-trigger="load"
|
|
style="height:300px;overflow-x: auto;">
|
|
<div class="animated-background"></div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if perms.employee.view_employeeworkinformation or request.user|is_reportingmanager %}
|
|
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
|
|
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
|
<span class="oh-card-dashboard__title">{% trans "Employee Work Information" %}</span>
|
|
</div>
|
|
<!-- Search bar -->
|
|
<div class="oh-search-bar mb-3">
|
|
<input type="text" hx-get="{% url 'emp-workinfo-complete' %}" hx-target="#pending"
|
|
hx-trigger="keyup changed delay:0.3s" id="employeeSearch" name="search"
|
|
placeholder="Search Employee">
|
|
</div>
|
|
<div class="oh-card-dashboard__body" hx-get="{% url 'emp-workinfo-complete' %}" hx-trigger="load">
|
|
<div class="animated-background"></div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="oh-modal" id="sendMailModal" role="dialog" aria-labelledby="sendMailModal" aria-hidden="true">
|
|
<div class="oh-modal__dialog">
|
|
<div class="oh-modal__dialog-header">
|
|
<span class="oh-modal__dialog-title" id="sendMailModalLabel">
|
|
<h5>{% trans 'Send Mail' %}</h5>
|
|
</span>
|
|
<button class="oh-modal__close" aria-label="Close"><ion-icon name="close-outline"></ion-icon></button>
|
|
</div>
|
|
<div class="oh-modal__dialog-body" id="mail-content"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="oh-modal" id="bigModal" role="dialog" aria-labelledby="bigModal" aria-hidden="true">
|
|
<div class="oh-modal__dialog">
|
|
<div class="oh-modal__dialog-header">
|
|
<h2 class="oh-modal__dialog-title" id="">
|
|
{% trans "Details" %}
|
|
</h2>
|
|
<button class="oh-modal__close" aria-label="Close">
|
|
<ion-icon name="close-outline"></ion-icon>
|
|
</button>
|
|
</div>
|
|
<div class="oh-modal__dialog-body oh-modal__dialog-relative" id="bigModalTarget"></div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="oh-modal" id="editModal" role="dialog" aria-labelledby="editModal" aria-hidden="true">
|
|
<div class="oh-modal__dialog">
|
|
<div class="oh-modal__dialog-header">
|
|
<h2 class="oh-modal__dialog-title" id="editModalLabel">
|
|
{% trans "Add Asset Report" %}
|
|
</h2>
|
|
<button type="button" class="oh-modal_close--custom"
|
|
onclick="$('#editModal').removeClass('oh-modal--show');">
|
|
<ion-icon name="close-outline" role="img" aria-label="close outline"></ion-icon>
|
|
</button>
|
|
</div>
|
|
<div class="oh-modal__dialog-body" id="editModalForm"></div>
|
|
</div>
|
|
</div>
|
|
|
|
{% include "announcement_single_view.html" %}
|
|
|
|
|
|
</main>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
|
|
<script src="{% static 'dashboard/getBirthday.js' %}"></script>
|
|
<script src="{% static 'dashboard/employeeChart.js' %}"></script>
|
|
|
|
{% if "leave"|app_installed %}
|
|
<script src="{% static 'dashboard/onLeave.js' %}"></script>
|
|
<script src="{% static 'dashboard/leaveChart.js' %}"></script>
|
|
{% endif %}
|
|
|
|
{% if "recruitment"|app_installed %}
|
|
{% if perms.recruitment.view_recruitment or request.user|is_stagemanager %}
|
|
<script src="{% static 'dashboard/recruitmentChart.js' %}"></script>
|
|
{% endif %}
|
|
{% 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 "onboarding"|app_installed %}
|
|
<!-- onboarding dashboard -->
|
|
<script src="{% static 'dashboard/onboardChart.js' %}"></script>
|
|
{% endif %}
|
|
|
|
{% if "pms"|app_installed %}
|
|
<!-- PMS chart -->
|
|
<script src="{% static 'src/dashboard/pmsChart.js' %}"></script>
|
|
{% endif %}
|
|
|
|
<!-- leave dashboard -->
|
|
<script>
|
|
|
|
// Function to remove the div after 20 seconds
|
|
function removeBirthdayDiv() {
|
|
const pageWrapper = document.querySelector('.page-wrapper');
|
|
if (pageWrapper) {
|
|
pageWrapper.remove(); // Remove the div
|
|
localStorage.setItem('birthdayShown', 'true'); // Set a flag in localStorage
|
|
}
|
|
}
|
|
|
|
// Check localStorage to see if the div has already been shown
|
|
if (!localStorage.getItem('birthdayShown')) {
|
|
// If not shown before, display the div
|
|
setTimeout(removeBirthdayDiv, 12000); // Remove after 12 seconds
|
|
} else {
|
|
// If already shown, remove it immediately (or don't add it at all)
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
const pageWrapper = document.querySelector('.page-wrapper');
|
|
if (pageWrapper) {
|
|
pageWrapper.remove(); // Remove if already shown
|
|
}
|
|
});
|
|
}
|
|
|
|
function setDifference(setA, setB) {
|
|
if (setB.length > setA.length) {
|
|
temp = setA
|
|
setA = setB
|
|
setB = temp
|
|
}
|
|
return [...setA.filter(element => !setB.includes(element))];
|
|
}
|
|
$(document).ready(function () {
|
|
function setDifference(arr1, arr2) {
|
|
return arr2.filter(id => !arr1.includes(id));
|
|
}
|
|
|
|
const defaultTileOrder = [
|
|
"notInYetId", "LeaveApprove", "shiftRequestApprove", "WorkTypeRequestApprove", "AttendanceValidate", "OTApprove",
|
|
"LeaveAllocationApprove", "feedbackAnswer", "assetRequestApprove", "movable8", "pendingHours", "notoutYetId",
|
|
"movable2", "movable3", "movable4", "movable1", "movable5", "movable6", "movable7", "movable9", "movable10", "movable11"
|
|
];
|
|
|
|
const allCurrentTileIds = $(".oh-card-dashboard--moveable[id]").map(function () {
|
|
return $(this).attr("id");
|
|
}).get();
|
|
|
|
// If tile order is not saved, initialize it
|
|
if (!localStorage.getItem("tileOrder")) {
|
|
localStorage.setItem("tileOrder", JSON.stringify(defaultTileOrder));
|
|
} else {
|
|
let storedIds = JSON.parse(localStorage.getItem("tileOrder")) || [];
|
|
|
|
// Add only new tiles (not already in storage) to the end
|
|
const newTileIds = setDifference(storedIds, allCurrentTileIds); // removes missing IDs
|
|
const missingTileIds = setDifference(allCurrentTileIds, storedIds); // adds new IDs
|
|
|
|
const updatedOrder = storedIds.filter(id => allCurrentTileIds.includes(id)); // clean invalid
|
|
const finalOrder = [...updatedOrder, ...missingTileIds];
|
|
|
|
localStorage.setItem("tileOrder", JSON.stringify(finalOrder));
|
|
}
|
|
|
|
// Reorder dashboard tiles based on tileOrder
|
|
function orderDashboardTile() {
|
|
const parentContainer = $("#tileContainer");
|
|
const orderIds = JSON.parse(localStorage.getItem("tileOrder")) || [];
|
|
|
|
const sortedElements = [];
|
|
for (const id of orderIds) {
|
|
const element = $("#" + id);
|
|
if (element.length) {
|
|
sortedElements.push(element);
|
|
}
|
|
}
|
|
|
|
if (sortedElements.length) {
|
|
parentContainer.empty();
|
|
for (const element of sortedElements) {
|
|
parentContainer.append(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
orderDashboardTile();
|
|
|
|
// Update tileOrder on mouseup
|
|
$(".oh-card-dashboard--moveable").on("mouseup", function () {
|
|
setTimeout(() => {
|
|
const newOrder = $(".oh-card-dashboard--moveable").map(function () {
|
|
return $(this).attr("id");
|
|
}).get();
|
|
|
|
localStorage.setItem("tileOrder", JSON.stringify(newOrder));
|
|
}, 10);
|
|
});
|
|
});
|
|
|
|
function closeNew(anchorElement) {
|
|
$(anchorElement).parent().find('#newTab').hide();
|
|
}
|
|
|
|
var w = c.width = window.innerWidth,
|
|
h = c.height = window.innerHeight,
|
|
ctx = c.getContext('2d'),
|
|
|
|
hw = w / 2, // half-width
|
|
hh = h / 2,
|
|
|
|
opts = {
|
|
strings: ['HAPPY', 'BIRTHDAY!', "{{request.user.employee_get|escapejs}}"],
|
|
charSize: 60,
|
|
charSpacing: 45,
|
|
lineHeight: 65,
|
|
cx: w / 2,
|
|
cy: h / 2,
|
|
fireworkPrevPoints: 10,
|
|
fireworkBaseLineWidth: 5,
|
|
fireworkAddedLineWidth: 8,
|
|
fireworkSpawnTime: 200,
|
|
fireworkBaseReachTime: 30,
|
|
fireworkAddedReachTime: 30,
|
|
fireworkCircleBaseSize: 20,
|
|
fireworkCircleAddedSize: 10,
|
|
fireworkCircleBaseTime: 30,
|
|
fireworkCircleAddedTime: 30,
|
|
fireworkCircleFadeBaseTime: 10,
|
|
fireworkCircleFadeAddedTime: 5,
|
|
fireworkBaseShards: 20,
|
|
fireworkAddedShards: 5,
|
|
fireworkShardPrevPoints: 3,
|
|
fireworkShardBaseVel: 4,
|
|
fireworkShardAddedVel: 2,
|
|
fireworkShardBaseSize: 10,
|
|
fireworkShardAddedSize: 3,
|
|
gravity: 0.1,
|
|
upFlow: -0.1,
|
|
letterContemplatingWaitTime: 360,
|
|
balloonSpawnTime: 10,
|
|
balloonBaseInflateTime: 10,
|
|
balloonAddedInflateTime: 10,
|
|
balloonBaseSize: 60,
|
|
balloonAddedSize: 20,
|
|
balloonBaseVel: 0.4,
|
|
balloonAddedVel: 0.4,
|
|
balloonBaseRadian: -(Math.PI / 2 - 0.5),
|
|
balloonAddedRadian: -1,
|
|
},
|
|
calc = {
|
|
totalWidth: opts.charSpacing * Math.max(opts.strings[0].length, opts.strings[1].length)
|
|
},
|
|
|
|
Tau = Math.PI * 2,
|
|
TauQuarter = Tau / 4,
|
|
|
|
letters = [];
|
|
|
|
ctx.font = opts.charSize + 'px "Lobster"';
|
|
|
|
|
|
function Letter(char, x, y) {
|
|
this.char = char;
|
|
this.x = x;
|
|
this.y = y;
|
|
|
|
this.dx = -ctx.measureText(char).width / 2;
|
|
this.dy = +opts.charSize / 2;
|
|
|
|
this.fireworkDy = this.y - hh;
|
|
|
|
var hue = x / calc.totalWidth * 360;
|
|
|
|
this.color = 'hsl(hue,80%,50%)'.replace('hue', hue);
|
|
this.lightAlphaColor = 'hsla(hue,80%,light%,alp)'.replace('hue', hue);
|
|
this.lightColor = 'hsl(hue,80%,light%)'.replace('hue', hue);
|
|
this.alphaColor = 'hsla(hue,80%,50%,alp)'.replace('hue', hue);
|
|
|
|
{% comment %} this.color = 'hsl(8, 77%, 56%)'; // Base color
|
|
this.lightAlphaColor = 'hsla(8, 77%, 56%, 0.5)'; // Semi-transparent
|
|
this.lightColor = 'hsla(8, 77%, 56%, 0.8)'; // Slightly transparent
|
|
this.alphaColor = 'hsla(8, 77%, 56%, 0.6)'; // Semi-transparent {% endcomment %}
|
|
|
|
|
|
this.reset();
|
|
}
|
|
Letter.prototype.reset = function () {
|
|
this.phase = 'firework';
|
|
this.tick = 0;
|
|
this.spawned = false;
|
|
this.spawningTime = opts.fireworkSpawnTime * Math.random() | 0;
|
|
this.reachTime = opts.fireworkBaseReachTime + opts.fireworkAddedReachTime * Math.random() | 0;
|
|
this.lineWidth = opts.fireworkBaseLineWidth + opts.fireworkAddedLineWidth * Math.random();
|
|
this.prevPoints = [[0, hh, 0]];
|
|
}
|
|
Letter.prototype.step = function () {
|
|
if (this.phase === 'firework') {
|
|
if (!this.spawned) {
|
|
++this.tick;
|
|
if (this.tick >= this.spawningTime) {
|
|
this.tick = 0;
|
|
this.spawned = true;
|
|
}
|
|
} else {
|
|
++this.tick;
|
|
|
|
var linearProportion = this.tick / this.reachTime,
|
|
harmonicProportion = Math.sin(linearProportion * TauQuarter),
|
|
|
|
x = linearProportion * this.x,
|
|
y = hh + harmonicProportion * this.fireworkDy;
|
|
|
|
if (this.prevPoints.length > opts.fireworkPrevPoints)
|
|
this.prevPoints.shift();
|
|
|
|
this.prevPoints.push([x, y, linearProportion * this.lineWidth]);
|
|
|
|
var lineWidthProportion = 1 / (this.prevPoints.length - 1);
|
|
|
|
for (var i = 1; i < this.prevPoints.length; ++i) {
|
|
var point = this.prevPoints[i],
|
|
point2 = this.prevPoints[i - 1];
|
|
|
|
ctx.strokeStyle = this.alphaColor.replace('alp', i / this.prevPoints.length);
|
|
ctx.lineWidth = point[2] * lineWidthProportion * i;
|
|
ctx.beginPath();
|
|
ctx.moveTo(point[0], point[1]);
|
|
ctx.lineTo(point2[0], point2[1]);
|
|
ctx.stroke();
|
|
}
|
|
|
|
if (this.tick >= this.reachTime) {
|
|
this.phase = 'contemplate';
|
|
|
|
this.circleFinalSize = opts.fireworkCircleBaseSize + opts.fireworkCircleAddedSize * Math.random();
|
|
this.circleCompleteTime = opts.fireworkCircleBaseTime + opts.fireworkCircleAddedTime * Math.random() | 0;
|
|
this.circleCreating = true;
|
|
this.circleFading = false;
|
|
|
|
this.circleFadeTime = opts.fireworkCircleFadeBaseTime + opts.fireworkCircleFadeAddedTime * Math.random() | 0;
|
|
this.tick = 0;
|
|
this.tick2 = 0;
|
|
|
|
this.shards = [];
|
|
|
|
var shardCount = opts.fireworkBaseShards + opts.fireworkAddedShards * Math.random() | 0,
|
|
angle = Tau / shardCount,
|
|
cos = Math.cos(angle),
|
|
sin = Math.sin(angle),
|
|
|
|
x = 1,
|
|
y = 0;
|
|
|
|
for (var i = 0; i < shardCount; ++i) {
|
|
var x1 = x;
|
|
x = x * cos - y * sin;
|
|
y = y * cos + x1 * sin;
|
|
|
|
this.shards.push(new Shard(this.x, this.y, x, y, this.alphaColor));
|
|
}
|
|
}
|
|
}
|
|
} else if (this.phase === 'contemplate') {
|
|
++this.tick;
|
|
|
|
if (this.circleCreating) {
|
|
++this.tick2;
|
|
var proportion = this.tick2 / this.circleCompleteTime,
|
|
harmonic = -Math.cos(proportion * Math.PI) / 2 + 0.5;
|
|
|
|
ctx.beginPath();
|
|
ctx.fillStyle = this.lightAlphaColor.replace('light', 50 + 50 * proportion).replace('alp', proportion);
|
|
ctx.arc(this.x, this.y, harmonic * this.circleFinalSize, 0, Tau);
|
|
ctx.fill();
|
|
|
|
if (this.tick2 > this.circleCompleteTime) {
|
|
this.tick2 = 0;
|
|
this.circleCreating = false;
|
|
this.circleFading = true;
|
|
}
|
|
} else if (this.circleFading) {
|
|
ctx.fillStyle = this.lightColor.replace('light', 70);
|
|
ctx.fillText(this.char, this.x + this.dx, this.y + this.dy);
|
|
|
|
++this.tick2;
|
|
var proportion = this.tick2 / this.circleFadeTime,
|
|
harmonic = -Math.cos(proportion * Math.PI) / 2 + 0.5;
|
|
|
|
ctx.beginPath();
|
|
ctx.fillStyle = this.lightAlphaColor.replace('light', 100).replace('alp', 1 - harmonic);
|
|
ctx.arc(this.x, this.y, this.circleFinalSize, 0, Tau);
|
|
ctx.fill();
|
|
|
|
if (this.tick2 >= this.circleFadeTime)
|
|
this.circleFading = false;
|
|
|
|
} else {
|
|
ctx.fillStyle = this.lightColor.replace('light', 70);
|
|
ctx.fillText(this.char, this.x + this.dx, this.y + this.dy);
|
|
}
|
|
|
|
for (var i = 0; i < this.shards.length; ++i) {
|
|
this.shards[i].step();
|
|
|
|
if (!this.shards[i].alive) {
|
|
this.shards.splice(i, 1);
|
|
--i;
|
|
}
|
|
}
|
|
|
|
if (this.tick > opts.letterContemplatingWaitTime) {
|
|
this.phase = 'balloon';
|
|
|
|
this.tick = 0;
|
|
this.spawning = true;
|
|
this.spawnTime = opts.balloonSpawnTime * Math.random() | 0;
|
|
this.inflating = false;
|
|
this.inflateTime = opts.balloonBaseInflateTime + opts.balloonAddedInflateTime * Math.random() | 0;
|
|
this.size = opts.balloonBaseSize + opts.balloonAddedSize * Math.random() | 0;
|
|
|
|
var rad = opts.balloonBaseRadian + opts.balloonAddedRadian * Math.random(),
|
|
vel = opts.balloonBaseVel + opts.balloonAddedVel * Math.random();
|
|
|
|
this.vx = Math.cos(rad) * vel;
|
|
this.vy = Math.sin(rad) * vel;
|
|
}
|
|
} else if (this.phase === 'balloon') {
|
|
ctx.strokeStyle = this.lightColor.replace('light', 80);
|
|
|
|
if (this.spawning) {
|
|
++this.tick;
|
|
ctx.fillStyle = this.lightColor.replace('light', 70);
|
|
ctx.fillText(this.char, this.x + this.dx, this.y + this.dy);
|
|
|
|
if (this.tick >= this.spawnTime) {
|
|
this.tick = 0;
|
|
this.spawning = false;
|
|
this.inflating = true;
|
|
}
|
|
} else if (this.inflating) {
|
|
++this.tick;
|
|
|
|
var proportion = this.tick / this.inflateTime,
|
|
x = this.cx = this.x,
|
|
y = this.cy = this.y - this.size * proportion;
|
|
|
|
ctx.fillStyle = this.alphaColor.replace('alp', proportion);
|
|
ctx.beginPath();
|
|
generateBalloonPath(x, y, this.size * proportion);
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y);
|
|
ctx.lineTo(x, this.y);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = this.lightColor.replace('light', 70);
|
|
ctx.fillText(this.char, this.x + this.dx, this.y + this.dy);
|
|
|
|
if (this.tick >= this.inflateTime) {
|
|
this.tick = 0;
|
|
this.inflating = false;
|
|
}
|
|
} else {
|
|
this.cx += this.vx;
|
|
this.cy += this.vy += opts.upFlow;
|
|
|
|
ctx.fillStyle = this.color;
|
|
ctx.beginPath();
|
|
generateBalloonPath(this.cx, this.cy, this.size);
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(this.cx, this.cy);
|
|
ctx.lineTo(this.cx, this.cy + this.size);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = this.lightColor.replace('light', 70);
|
|
ctx.fillText(this.char, this.cx + this.dx, this.cy + this.dy + this.size);
|
|
|
|
if (this.cy + this.size < -hh || this.cx < -hw || this.cy > hw)
|
|
this.phase = 'done';
|
|
}
|
|
}
|
|
}
|
|
function Shard(x, y, vx, vy, color) {
|
|
var vel = opts.fireworkShardBaseVel + opts.fireworkShardAddedVel * Math.random();
|
|
|
|
this.vx = vx * vel;
|
|
this.vy = vy * vel;
|
|
|
|
this.x = x;
|
|
this.y = y;
|
|
|
|
this.prevPoints = [[x, y]];
|
|
this.color = color;
|
|
|
|
this.alive = true;
|
|
|
|
this.size = opts.fireworkShardBaseSize + opts.fireworkShardAddedSize * Math.random();
|
|
}
|
|
Shard.prototype.step = function () {
|
|
this.x += this.vx;
|
|
this.y += this.vy += opts.gravity;
|
|
|
|
if (this.prevPoints.length > opts.fireworkShardPrevPoints)
|
|
this.prevPoints.shift();
|
|
|
|
this.prevPoints.push([this.x, this.y]);
|
|
|
|
var lineWidthProportion = this.size / this.prevPoints.length;
|
|
|
|
for (var k = 0; k < this.prevPoints.length - 1; ++k) {
|
|
var point = this.prevPoints[k],
|
|
point2 = this.prevPoints[k + 1];
|
|
|
|
ctx.strokeStyle = this.color.replace('alp', k / this.prevPoints.length);
|
|
ctx.lineWidth = k * lineWidthProportion;
|
|
ctx.beginPath();
|
|
ctx.moveTo(point[0], point[1]);
|
|
ctx.lineTo(point2[0], point2[1]);
|
|
ctx.stroke();
|
|
}
|
|
|
|
if (this.prevPoints[0][1] > hh)
|
|
this.alive = false;
|
|
}
|
|
function generateBalloonPath(x, y, size) {
|
|
ctx.moveTo(x, y);
|
|
ctx.bezierCurveTo(x - size / 2, y - size / 2,
|
|
x - size / 4, y - size,
|
|
x, y - size);
|
|
ctx.bezierCurveTo(x + size / 4, y - size,
|
|
x + size / 2, y - size / 2,
|
|
x, y);
|
|
}
|
|
|
|
function anim() {
|
|
window.requestAnimationFrame(anim);
|
|
|
|
// Clear the canvas for the next frame
|
|
ctx.clearRect(0, 0, w, h);
|
|
|
|
ctx.translate(hw, hh);
|
|
|
|
var done = true;
|
|
for (var l = 0; l < letters.length; ++l) {
|
|
letters[l].step();
|
|
if (letters[l].phase !== 'done') done = false;
|
|
}
|
|
|
|
ctx.translate(-hw, -hh);
|
|
|
|
if (done)
|
|
for (var l = 0; l < letters.length; ++l)
|
|
letters[l].reset();
|
|
}
|
|
|
|
for (var i = 0; i < opts.strings.length; ++i) {
|
|
for (var j = 0; j < opts.strings[i].length; ++j) {
|
|
letters.push(new Letter(opts.strings[i][j],
|
|
j * opts.charSpacing + opts.charSpacing / 2 - opts.strings[i].length * opts.charSize / 2,
|
|
i * opts.lineHeight + opts.lineHeight / 2 - opts.strings.length * opts.lineHeight / 2));
|
|
}
|
|
}
|
|
|
|
anim();
|
|
|
|
window.addEventListener('resize', function () {
|
|
w = c.width = window.innerWidth;
|
|
h = c.height = window.innerHeight;
|
|
|
|
hw = w / 2;
|
|
hh = h / 2;
|
|
|
|
ctx.font = opts.charSize + 'px Verdana';
|
|
})
|
|
|
|
</script>
|
|
<script src="{% static 'build/js/dashboardDriver.js' %}"></script>
|
|
|
|
{% if not request.user.driverviewed_set.first or "dashboard" not in request.user.driverviewed_set.first.user_viewed %}
|
|
<script>
|
|
runDriver()
|
|
</script>
|
|
{% endif %}
|