[ADD] PMS: Feedback overview
This commit is contained in:
@@ -546,6 +546,26 @@ class Feedback(HorillaModel):
|
||||
def __str__(self):
|
||||
return f"{self.employee_id.employee_first_name} - {self.review_cycle}"
|
||||
|
||||
def requested_employees(self):
|
||||
manager = self.manager_id
|
||||
colleagues = self.colleague_id.all()
|
||||
subordinates = self.subordinate_id.all()
|
||||
owner = self.employee_id
|
||||
|
||||
employees = [employee for employee in subordinates]
|
||||
|
||||
for employee in colleagues:
|
||||
if employee not in employees:
|
||||
employees.append(employee)
|
||||
|
||||
if manager not in employees:
|
||||
employees.append(manager)
|
||||
|
||||
if owner not in employees:
|
||||
employees.append(owner)
|
||||
|
||||
return employees
|
||||
|
||||
|
||||
class AnonymousFeedback(models.Model):
|
||||
"""feedback model for creating feedback"""
|
||||
|
||||
@@ -3,314 +3,432 @@
|
||||
{% load static i18n %}
|
||||
{% load i18n %}
|
||||
{% load basefilters %}
|
||||
{% load mathfilters %}
|
||||
|
||||
<style>
|
||||
.oh-profile__avatar-limit-height {
|
||||
height: 30px !important;
|
||||
}
|
||||
.oh-profile_name_custom {
|
||||
font-size: 13px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
.oh-profile__image_custm {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
}
|
||||
.avatars {
|
||||
display: flex;
|
||||
padding: 8px 10px 8px 10px;
|
||||
}
|
||||
|
||||
.avatars__item {
|
||||
background-color: #596376;
|
||||
border: 2px solid white;
|
||||
border-radius: 100%;
|
||||
color: #ffffff;
|
||||
display: block;
|
||||
font-family: sans-serif;
|
||||
font-size: 12px;
|
||||
font-weight: 100;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
line-height: 17px;
|
||||
text-align: center;
|
||||
transition: margin 0.1s ease-in-out;
|
||||
overflow: hidden;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.avatars__item:first-child {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.avatars__item:nth-child(2) {
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.avatars__item:nth-child(3) {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.avatars__item:nth-child(4) {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.avatars__item:nth-child(5) {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.avatars__item:last-child {
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.avatars__item img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.avatars:hover .avatars__item {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
<div id="message"></div>
|
||||
<main :class="sidebarOpen ? 'oh-main__sidebar-visible' : ''">
|
||||
<section class="oh-wrapper oh-main__topbar">
|
||||
<div class="oh-main__titlebar oh-main__titlebar--left oh-d-flex-column--resp oh-mb-3--small">
|
||||
<h1 class="oh-main__titlebar-title fw-bold">{% trans "Feedback" %}: {{feedback.review_cycle}}</h1>
|
||||
<div class="d-flex align-items-center mt-3">
|
||||
<div class="oh-profile oh-profile--md" title="Owner">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{feedback.employee_id.get_avatar}}" class="oh-profile__image"
|
||||
alt="." />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark">{{feedback.employee_id}}</span>
|
||||
|
||||
</div>
|
||||
<select id="status" class="oh-select oh-select--sm ms-3" name="feedback_status" title="Status"
|
||||
hx-post="{%url 'feedback-detailed-view-status' id=feedback.id %}"
|
||||
hx-trigger="change" hx-target="#message">
|
||||
<option value="{{feedback.status}}" selected>
|
||||
{% trans feedback.get_status_display %}
|
||||
</option>
|
||||
{%for value,label in feedback_status %}
|
||||
{% if feedback.status != label %}
|
||||
<option value="{{label}}">{% trans label %}</option>
|
||||
{% endif%}
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="oh-wrapper mb-2">
|
||||
<div class="oh-card">
|
||||
<div class="oh-main__titlebar oh-d-flex-column--resp oh-mb-3--small">
|
||||
<h1 class="oh-main__titlebar-title fw-bold">{% trans "Feedback" %}: {{feedback}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<!-- checking userlevel -->
|
||||
{% if perms.pms.delete_feedback or request.user|filtersubordinates %}
|
||||
<div class="oh-main__titlebar oh-main__titlebar--right">
|
||||
<div class="oh-btn-group m-2">
|
||||
<div class="oh-btn-group" >
|
||||
<form action="{% url 'feedback-archive' id=feedback.id %}" method="post" onsubmit="return confirm('{% trans "Do you want archive this Feedback ?" %}')" >
|
||||
<button class="oh-btn w-100 " title="{% trans 'Archive' %}" style="background-color: white;!important">
|
||||
{% csrf_token %}
|
||||
<ion-icon name="archive-sharp" type="submit"></ion-icon>
|
||||
</button>
|
||||
</form>
|
||||
{% if perms.pms.delete_feedback %}
|
||||
<form action="{% url 'feedback-delete' id=feedback.id %}" method="post" onsubmit="return confirm('{% trans "Do you want Delete this Feedback ?" %}')">
|
||||
{% csrf_token %}
|
||||
<button class="oh-btn oh-btn--danger-outline w-100" title="{% trans 'Delete' %}" style="background-color: white;!important">
|
||||
<ion-icon name="trash-outline" role="img" class="md hydrated" aria-label="trash outline"></ion-icon>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="align-items-center d-flex justify-content-between">
|
||||
<div class="oh-profile oh-profile--md" title="Owner">
|
||||
<span class="mr-2" style="font-size:15px;">{% trans "Owner: " %}</span>
|
||||
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{feedback.employee_id.get_avatar}}" class="oh-profile__image"
|
||||
alt="." />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark">{{feedback.employee_id}}</span>
|
||||
</div>
|
||||
{% if perms.pms.delete_feedback or request.user|filtersubordinates %}
|
||||
<div class="oh-main__titlebar oh-main__titlebar--right justify-content-end">
|
||||
<select id="status" class="oh-select oh-select--sm ms-3" name="feedback_status" title="Status"
|
||||
hx-post="{%url 'feedback-detailed-view-status' id=feedback.id %}"
|
||||
hx-trigger="change" hx-target="#message">
|
||||
<option value="{{feedback.status}}" selected>
|
||||
{% trans feedback.get_status_display %}
|
||||
</option>
|
||||
{%for value,label in feedback_status %}
|
||||
{% if feedback.status != label %}
|
||||
<option value="{{label}}">{% trans label %}</option>
|
||||
{% endif%}
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="oh-btn-group m-2">
|
||||
<form action="{% url 'feedback-archive' id=feedback.id %}" method="post" onsubmit="return confirm('{% trans "Do you want archive this Feedback ?" %}')" >
|
||||
<button class="oh-btn w-100 " title="{% trans 'Archive' %}" style="background-color: white;!important">
|
||||
{% csrf_token %}
|
||||
<ion-icon name="archive-sharp" type="submit"></ion-icon>
|
||||
</button>
|
||||
</form>
|
||||
{% if perms.pms.delete_feedback %}
|
||||
<form action="{% url 'feedback-delete' id=feedback.id %}" method="post" onsubmit="return confirm('{% trans "Do you want Delete this Feedback ?" %}')">
|
||||
{% csrf_token %}
|
||||
<button class="oh-btn oh-btn--danger-outline w-100" title="{% trans 'Delete' %}" style="background-color: white;!important">
|
||||
<ion-icon name="trash-outline" role="img" class="md hydrated" aria-label="trash outline"></ion-icon>
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div >
|
||||
<div class="align-items-center d-flex">
|
||||
<span class="mr-2" style="font-size:15px;">{% trans "Due on: " %}</span>
|
||||
<span class="d-flex justify-content-between">{{feedback.end_date}}</span>
|
||||
<span class='d-flex justify-content-between align-items-center ml-2'
|
||||
>
|
||||
<span title = 'due {% if feedback.end_date == today %} today {% else %}in {{feedback.end_date|sub:today}}{% endif %}'>
|
||||
<ion-icon
|
||||
class="text-{% if feedback.end_date < today %}danger {% elif feedback.end_date == today %}warning {% else %}success{% endif %}"
|
||||
name="time-sharp"
|
||||
>
|
||||
</ion-icon>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="align-items-center d-flex">
|
||||
<span class="mr-2" style="font-size:15px;">{% trans "Answered employees: " %}</span>
|
||||
<div class="d-flex justify-content-between custom-scroll">
|
||||
<div class="avatars" id="avatarsContainer">
|
||||
{% for employee in employee_statics.yes %}
|
||||
<a
|
||||
href="{% url 'employee-view-individual' employee.id %}"
|
||||
class="avatars__item"
|
||||
title="{{employee}}"
|
||||
><img class="avatar" src="{{employee.get_avatar}}" alt=""
|
||||
/></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="align-items-center d-flex">
|
||||
<span class="mr-2" style="font-size:15px;" >{% trans "Employees not answerd yet: " %}</span>
|
||||
<div class="d-flex justify-content-between custom-scroll">
|
||||
<div class="avatars" id="avatarsContainer">
|
||||
{% for employee in employee_statics.no %}
|
||||
<a
|
||||
href="{% url 'employee-view-individual' employee.id %}"
|
||||
class="avatars__item"
|
||||
title="{{employee}}"
|
||||
><img class="avatar" src="{{employee.get_avatar}}" alt=""
|
||||
/></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- checking userlevel -->
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="oh-wrapper mb-2">
|
||||
<div class="oh-card p-4">
|
||||
{% if perms.pms.change_feedback and not feedback_started %}
|
||||
<div class="d-flex flex-row-reverse">
|
||||
<button
|
||||
class="oh-btn oh-btn--x-small d-flex align-items-center ms-2 "
|
||||
data-toggle="oh-modal-toggle"
|
||||
data-target="#feedbackModalPopup"
|
||||
hx-get="{%url 'feedback-update' id=feedback.id %}"
|
||||
hx-target="#feedbackModalTarget">
|
||||
<ion-icon name="create-outline" class="me-1" ></ion-icon>
|
||||
{% trans "Edit" %}
|
||||
<div class="oh-tabs" >
|
||||
<ul class="oh-tabs__tablist" >
|
||||
<li class="oh-tabs__tab oh-tabs__tab--active" onclick="switchTab(event);" data-target="#feedback-answers">
|
||||
{% trans "Feedback Answers" %}
|
||||
</li>
|
||||
<li class="oh-tabs__tab" onclick="switchTab(event);$('#feedback-overview-button').click()" data-target="#feedback-overview">
|
||||
{% trans "Feedback Overview" %}
|
||||
</li>
|
||||
</ul>
|
||||
<div class="oh-tabs__contents">
|
||||
<!-- feddback answers -->
|
||||
<div class="oh-tabs__content oh-tabs__content--active" id="feedback-answers">
|
||||
<div class="oh-card p-4">
|
||||
{% if perms.pms.change_feedback and not feedback_started %}
|
||||
<div class="d-flex flex-row-reverse">
|
||||
<button
|
||||
class="oh-btn oh-btn--x-small d-flex align-items-center ms-2 "
|
||||
data-toggle="oh-modal-toggle"
|
||||
data-target="#feedbackModalPopup"
|
||||
hx-get="{%url 'feedback-update' id=feedback.id %}"
|
||||
hx-target="#feedbackModalTarget">
|
||||
<ion-icon name="create-outline" class="me-1" ></ion-icon>
|
||||
{% trans "Edit" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="m-2">
|
||||
<div class="oh-card__body">
|
||||
<div class="oh-sticky-table">
|
||||
<div class="oh-sticky-table__table">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Employee" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
|
||||
<div class="oh-sticky-table__th"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<ul class="oh-sticky-table___profile-list">
|
||||
<li class="oh-sticky-table__profile-item">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{feedback.employee_id.get_avatar}}"
|
||||
class="oh-profile__image" alt="{{feedback.employee_id}}" />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"> {{feedback.employee_id}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class=""></span><span class="feedback-status" x-data-feedback-id="{{feedback.id}}" x-data-employee-id="{{feedback.employee_id.id}}"> </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td"><button
|
||||
class="oh-btn oh-btn--secondary oh-activity-sidebar__open"
|
||||
data-target="#answerViewAccordion" hx-post="{%url 'feedback-detailed-view-answer' id=feedback.id emp_id=feedback.employee_id.id %}" hx-target="#answerView">{% trans "Answer View" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- manager section -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="m-2">
|
||||
<div class="oh-card__body">
|
||||
<div class="oh-sticky-table">
|
||||
<div class="oh-sticky-table__table">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Manager" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
|
||||
<div class="oh-sticky-table__th"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<ul class="oh-sticky-table___profile-list">
|
||||
<li class="oh-sticky-table__profile-item">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{feedback.manager_id.get_avatar}}"
|
||||
class="oh-profile__image" alt="{{feedback.employee_id}}" />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"> {{feedback.manager_id}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class=""></span><span class="feedback-status" x-data-feedback-id="{{feedback.id}}" x-data-employee-id="{{feedback.manager_id.id}}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td"><button
|
||||
class="oh-btn oh-btn--secondary oh-activity-sidebar__open"
|
||||
data-target="#answerViewAccordion" hx-post="{%url 'feedback-detailed-view-answer' id=feedback.id emp_id=feedback.manager_id.id %}" hx-target="#answerView">{% trans "Answer View" %}
|
||||
</button></div>
|
||||
</div>
|
||||
<!-- manager answer off canvas -->
|
||||
<div class="oh-activity-sidebar" id="managerAnswer">
|
||||
<div class="oh-activity-sidebar__header">
|
||||
<ion-icon name="chevron-back-outline"
|
||||
class="oh-activity-sidebar__header-icon me-2 oh-activity-sidebar__close"
|
||||
data-target="#managerAnswer"></ion-icon>
|
||||
<span class="oh-activity-sidebar__title"> {% trans "Answers" %}</span>
|
||||
</div>
|
||||
<div class="oh-activity-sidebar__body">
|
||||
<ol class="oh-activity-sidebar__qa-list" role="list">
|
||||
{% for answer in manager_answers %}
|
||||
{% include 'feedback/feedback_detailed_view_answer.html' %}
|
||||
{%endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!-- endof manager answer off canvas -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- subordinate section -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="m-2">
|
||||
<div class="oh-card__body">
|
||||
<div class="oh-sticky-table">
|
||||
<div class="oh-sticky-table__table">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Subordinates" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
|
||||
<div class="oh-sticky-table__th"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for employee in feedback.subordinate_id.all %}
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<ul class="oh-sticky-table___profile-list">
|
||||
<li class="oh-sticky-table__profile-item">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{employee.get_avatar}}"
|
||||
class="oh-profile__image" alt="" />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"> {{employee}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class=""></span ><span class="feedback-status" x-data-feedback-id="{{feedback.id}}" x-data-employee-id="{{employee.id}}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td"><button
|
||||
class="oh-btn oh-btn--secondary oh-activity-sidebar__open"
|
||||
data-target="#answerViewAccordion" hx-post="{%url 'feedback-detailed-view-answer' id=feedback.id emp_id=employee.id %}" hx-target="#answerView">{% trans "Answer View" %}
|
||||
</button></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end of subordinate section -->
|
||||
|
||||
<!-- Colleague section -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="m-2">
|
||||
<div class="oh-card__body">
|
||||
<div class="oh-sticky-table">
|
||||
<div class="oh-sticky-table__table">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Colleague" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
|
||||
<div class="oh-sticky-table__th"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for employee in feedback.colleague_id.all %}
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<ul class="oh-sticky-table___profile-list">
|
||||
<li class="oh-sticky-table__profile-item">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{employee.get_avatar}}"
|
||||
class="oh-profile__image" alt="" />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"> {{employee}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class=""></span><span class="feedback-status" x-data-feedback-id="{{feedback.id}}" x-data-employee-id="{{employee.id}}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td"><button
|
||||
class="oh-btn oh-btn--secondary oh-activity-sidebar__open"
|
||||
data-target="#answerViewAccordion" hx-post="{%url 'feedback-detailed-view-answer' id=feedback.id emp_id=employee.id %}" hx-target="#answerView">{% trans "Answer View" %}
|
||||
</button></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- endof colleague section -->
|
||||
</div>
|
||||
<div class="oh-tabs__content" id="feedback-overview">
|
||||
<div id="feedback_overview_div">
|
||||
<button hx-get="{% url 'get-feedback-overview' feedback.id %}"
|
||||
hx-target="#feedback-overview" id="feedback-overview-button" hidden>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="p-2 m-2">
|
||||
<div class="oh-card__body">
|
||||
<div class="oh-sticky-table">
|
||||
<div class="oh-sticky-table__table">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Employee" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Due" %}</div>
|
||||
<div class="oh-sticky-table__th"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<ul class="oh-sticky-table___profile-list">
|
||||
<li class="oh-sticky-table__profile-item">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{feedback.employee_id.get_avatar}}"
|
||||
class="oh-profile__image" alt="{{feedback.employee_id}}" />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"> {{feedback.employee_id}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class=""></span><span class="feedback-status" x-data-feedback-id="{{feedback.id}}" x-data-employee-id="{{feedback.employee_id.id}}"> </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
{{ current_date|timesince:feedback.end_date }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td"><button
|
||||
class="oh-btn oh-btn--secondary oh-activity-sidebar__open"
|
||||
data-target="#answerViewAccordion" hx-post="{%url 'feedback-detailed-view-answer' id=feedback.id emp_id=feedback.employee_id.id %}" hx-target="#answerView">{% trans "Answer View" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- manager section -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="p-2 m-2">
|
||||
<div class="oh-card__body">
|
||||
<div class="oh-sticky-table">
|
||||
<div class="oh-sticky-table__table">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Manager" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Due" %}</div>
|
||||
<div class="oh-sticky-table__th"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<ul class="oh-sticky-table___profile-list">
|
||||
<li class="oh-sticky-table__profile-item">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{feedback.manager_id.get_avatar}}"
|
||||
class="oh-profile__image" alt="{{feedback.employee_id}}" />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"> {{feedback.manager_id}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class=""></span><span class="feedback-status" x-data-feedback-id="{{feedback.id}}" x-data-employee-id="{{feedback.manager_id.id}}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
{{ current_date|timesince:feedback.end_date }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td"><button
|
||||
class="oh-btn oh-btn--secondary oh-activity-sidebar__open"
|
||||
data-target="#answerViewAccordion" hx-post="{%url 'feedback-detailed-view-answer' id=feedback.id emp_id=feedback.manager_id.id %}" hx-target="#answerView">{% trans "Answer View" %}
|
||||
</button></div>
|
||||
</div>
|
||||
<!-- manager answer off canvas -->
|
||||
<div class="oh-activity-sidebar" id="managerAnswer">
|
||||
<div class="oh-activity-sidebar__header">
|
||||
<ion-icon name="chevron-back-outline"
|
||||
class="oh-activity-sidebar__header-icon me-2 oh-activity-sidebar__close"
|
||||
data-target="#managerAnswer"></ion-icon>
|
||||
<span class="oh-activity-sidebar__title"> {% trans "Answers" %}</span>
|
||||
</div>
|
||||
<div class="oh-activity-sidebar__body">
|
||||
<ol class="oh-activity-sidebar__qa-list" role="list">
|
||||
{% for answer in manager_answers %}
|
||||
{% include 'feedback/feedback_detailed_view_answer.html' %}
|
||||
{%endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!-- endof manager answer off canvas -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- subordinate section -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="p-2 m-2">
|
||||
<div class="oh-card__body">
|
||||
<div class="oh-sticky-table">
|
||||
<div class="oh-sticky-table__table">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Subordinates" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Due" %}</div>
|
||||
<div class="oh-sticky-table__th"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for employee in feedback.subordinate_id.all %}
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<ul class="oh-sticky-table___profile-list">
|
||||
<li class="oh-sticky-table__profile-item">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{employee.get_avatar}}"
|
||||
class="oh-profile__image" alt="" />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"> {{employee}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class=""></span ><span class="feedback-status" x-data-feedback-id="{{feedback.id}}" x-data-employee-id="{{employee.id}}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
{{ current_date|timesince:feedback.end_date }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td"><button
|
||||
class="oh-btn oh-btn--secondary oh-activity-sidebar__open"
|
||||
data-target="#answerViewAccordion" hx-post="{%url 'feedback-detailed-view-answer' id=feedback.id emp_id=employee.id %}" hx-target="#answerView">{% trans "Answer View" %}
|
||||
</button></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end of subordinate section -->
|
||||
|
||||
<!-- Colleague section -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="p-2 m-2">
|
||||
<div class="oh-card__body">
|
||||
<div class="oh-sticky-table">
|
||||
<div class="oh-sticky-table__table">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Colleague" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Due" %}</div>
|
||||
<div class="oh-sticky-table__th"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for employee in feedback.colleague_id.all %}
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<ul class="oh-sticky-table___profile-list">
|
||||
<li class="oh-sticky-table__profile-item">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{employee.get_avatar}}"
|
||||
class="oh-profile__image" alt="" />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"> {{employee}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class=""></span><span class="feedback-status" x-data-feedback-id="{{feedback.id}}" x-data-employee-id="{{employee.id}}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="d-flex align-items-center">
|
||||
{{feedback.end_date|timeuntil}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td"><button
|
||||
class="oh-btn oh-btn--secondary oh-activity-sidebar__open"
|
||||
data-target="#answerViewAccordion" hx-post="{%url 'feedback-detailed-view-answer' id=feedback.id emp_id=employee.id %}" hx-target="#answerView">{% trans "Answer View" %}
|
||||
</button></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- endof colleague section -->
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- answer off canvas -->
|
||||
|
||||
155
pms/templates/feedback/feedback_overview.html
Normal file
155
pms/templates/feedback/feedback_overview.html
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
{% load i18n %}
|
||||
<div class="oh-card">
|
||||
<div class="oh-accordion-meta">
|
||||
{% for question,answers in feedback_overview.items %}
|
||||
<div class="oh-accordion-meta__item">
|
||||
<div class="oh-accordion-meta__header" onclick='$(this).toggleClass("oh-accordion-meta__header--show");'>
|
||||
<span class="oh-accordion-meta__title pt-3 pb-3">
|
||||
<div class="oh-tabs__input-badge-container">
|
||||
<span
|
||||
class="oh-badge oh-badge--round mr-1"
|
||||
>
|
||||
{{question}}
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div class="oh-accordion-meta__body d-none">
|
||||
<div class="oh-sticky-table oh-sticky-table--no-overflow">
|
||||
<div class="oh-sticky-table">
|
||||
<div class="oh-sticky-table__table oh-table--sortable">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Employee" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Answer" %}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for answer in answers %}
|
||||
{% for key,value in answer.items %}
|
||||
<div class="oh-sticky-table__tr" draggable="true">
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img
|
||||
src="{{key.get_avatar}}"
|
||||
class="oh-profile__image"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark">{{key}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
{% if value.1.type == '1' %}
|
||||
<span class="oh-activity-sidebar__a">{{ value.0.answer}}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if value.1.type == '2' %}
|
||||
<div class="d-block mb-0">
|
||||
<div class="oh-rate">
|
||||
<input type="radio" id="star5" value="5" disabled {% if value.0.answer == '5' %} checked {% endif %} />
|
||||
<label for="star5" title="5 Stars">5 {% trans "Stars" %}</label>
|
||||
<input type="radio" id="star4" value="4" disabled {% if value.0.answer == '4' %} checked {% endif %} />
|
||||
<label for="star4" title="4 Stars">4 {% trans "Stars" %}</label>
|
||||
<input type="radio" id="star3" value="3" disabled {% if value.0.answer == '3' %} checked {% endif %} />
|
||||
<label for="star3" title="3 Stars">3 {% trans "Stars" %}</label>
|
||||
<input type="radio" id="star2" value="2" disabled {% if value.0.answer == '2' %} checked {% endif %} />
|
||||
<label for="star2" title="2 Stars">2 {% trans "Stars" %}</label>
|
||||
<input type="radio" id="star1" value="1" disabled {% if value.0.answer == '1' %} checked {% endif %} />
|
||||
<label for="star1" title="1 Star">1 {% trans "Star" %}</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if value.1.type == '3' %}
|
||||
<div class="oh-input__group">
|
||||
<div class="oh-input-picker-group">
|
||||
<div class="oh-input-picker oh-input-picker--selected boolean-colour ">
|
||||
{{value.0.answer}}
|
||||
<input type="radio" selected />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if value.1.type == '4' %}
|
||||
<div class="d-block">
|
||||
<label class="oh-label" for="answer1"> {{value.0.answer}}</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if value.1.type == '5' %}
|
||||
<div class="d-block">
|
||||
<div class="oh-input-picker-group oh-input-picker-group--resp mt-2">
|
||||
<div class="oh-input-picker oh-input-picker--likert likert-colour oh-input-picker--selected ">
|
||||
{{value.0.answer}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
$(document).ready(function () {
|
||||
// answer color for likert
|
||||
var booleanText = $('.boolean-colour').text().trim()
|
||||
var booleanEl = $('.boolean-colour')
|
||||
var red = "oh-input-picker--1"
|
||||
var orange = "oh-input-picker--2"
|
||||
var yellow = "oh-input-picker--3"
|
||||
var light_green = "oh-input-picker--4"
|
||||
var green = "oh-input-picker--5"
|
||||
|
||||
$('.likert-colour').each(function() {
|
||||
var likertText = $(this).text().trim()
|
||||
|
||||
if (likertText === 'Strongly Agree'){
|
||||
$(this).addClass(green)
|
||||
}
|
||||
else if (likertText === 'Agree'){
|
||||
$(this).addClass(light_green)
|
||||
}
|
||||
else if (likertText === 'Neutral'){
|
||||
$(this).addClass(yellow)
|
||||
}
|
||||
else if (likertText === 'Disagree'){
|
||||
$(this).addClass(orange)
|
||||
}
|
||||
else if (likertText === 'Strongly Disagree'){
|
||||
$(this).addClass(red)
|
||||
}
|
||||
});
|
||||
|
||||
// boolean text colour adding
|
||||
$('.boolean-colour').each(function() {
|
||||
var booleanText = $(this).text().trim()
|
||||
|
||||
if (booleanText === 'yes'){
|
||||
$(this).addClass(green)
|
||||
}
|
||||
else if (booleanText === 'no'){
|
||||
$(this).addClass(red)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -167,6 +167,11 @@ urlpatterns = [
|
||||
views.feedback_detailed_view_status,
|
||||
name="feedback-detailed-view-status",
|
||||
),
|
||||
path(
|
||||
"get-feedback-overview/<int:obj_id>",
|
||||
views.get_feedback_overview,
|
||||
name="get-feedback-overview",
|
||||
),
|
||||
path("feedback-status", views.feedback_status, name="feedback-status"),
|
||||
path(
|
||||
"question-creation/<int:id>", views.question_creation, name="question-creation"
|
||||
|
||||
48
pms/views.py
48
pms/views.py
@@ -1782,12 +1782,23 @@ def feedback_detailed_view(request, id, **kwargs):
|
||||
)
|
||||
if is_have_perm:
|
||||
feedback_started = Answer.objects.filter(feedback_id=id)
|
||||
current_date = datetime.datetime.now()
|
||||
employees = feedback.requested_employees()
|
||||
yes = []
|
||||
no = []
|
||||
for employee in employees:
|
||||
if Answer.objects.filter(
|
||||
feedback_id=feedback, employee_id=employee
|
||||
).exists():
|
||||
yes.append(employee)
|
||||
else:
|
||||
no.append(employee)
|
||||
employee_statics = {"yes": yes, "no": no}
|
||||
context = {
|
||||
"feedback": feedback,
|
||||
"feedback_started": feedback_started,
|
||||
"feedback_status": Feedback.STATUS_CHOICES,
|
||||
"current_date": current_date,
|
||||
"employee_statics": employee_statics,
|
||||
"today": datetime.datetime.today().date(),
|
||||
}
|
||||
return render(request, "feedback/feedback_detailed_view.html", context)
|
||||
else:
|
||||
@@ -2026,6 +2037,39 @@ def feedback_detailed_view_status(request, id):
|
||||
return render(request, "message.html")
|
||||
|
||||
|
||||
@login_required
|
||||
def get_feedback_overview(request, obj_id):
|
||||
"""
|
||||
overview of feedback
|
||||
"""
|
||||
feedback = Feedback.objects.filter(id=obj_id).first() if obj_id else None
|
||||
if feedback and check_permission_feedback_detailed_view(
|
||||
request, feedback, perm="pms.view_feedback"
|
||||
):
|
||||
question_template = feedback.question_template_id
|
||||
questions = question_template.question.all()
|
||||
feedback_answers = feedback.feedback_answer.all()
|
||||
feedback_overview = {}
|
||||
for question in questions:
|
||||
answer_list = []
|
||||
for answer in feedback_answers:
|
||||
if answer.question_id == question:
|
||||
answer_list.append(
|
||||
{
|
||||
answer.employee_id: [
|
||||
answer.answer,
|
||||
{"type": answer.question_id.question_type},
|
||||
]
|
||||
}
|
||||
)
|
||||
feedback_overview[question] = answer_list
|
||||
return render(
|
||||
request,
|
||||
"feedback/feedback_overview.html",
|
||||
context={"feedback_overview": feedback_overview},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def feedback_archive(request, id):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user