[UPDT] PMS: Bulk feedback create form is updated with title suggestion
This commit is contained in:
50
pms/cbvs.py
50
pms/cbvs.py
@@ -1,11 +1,12 @@
|
||||
from typing import Any
|
||||
|
||||
from django import template
|
||||
from django.contrib import messages
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.translation import gettext_lazy as _trans
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from base.methods import filter_own_and_subordinate_recordes, is_reportingmanager
|
||||
from employee.models import Employee
|
||||
@@ -59,7 +60,7 @@ class BonusPointSettingNavView(views.HorillaNavView):
|
||||
data-target="#genericModal"
|
||||
"""
|
||||
|
||||
nav_title = _trans("Bonus Point Setting")
|
||||
nav_title = _("Bonus Point Setting")
|
||||
search_url = reverse_lazy("bonus-point-setting-list-view")
|
||||
search_swap_target = "#listContainer"
|
||||
|
||||
@@ -73,7 +74,7 @@ class BonusPointSettingFormView(views.HorillaFormView):
|
||||
|
||||
form_class = BonusPointSettingForm
|
||||
model = models.BonusPointSetting
|
||||
new_display_title = _trans("Create Bonus Point Setting")
|
||||
new_display_title = _("Create Bonus Point Setting")
|
||||
template_name = "bonus/bonus_form.html"
|
||||
|
||||
def get_form_kwargs(self):
|
||||
@@ -102,7 +103,7 @@ class BonusPointSettingFormView(views.HorillaFormView):
|
||||
message = "Bonus Point Setting updated"
|
||||
form.save()
|
||||
|
||||
messages.success(self.request, _trans(message))
|
||||
messages.success(self.request, _(message))
|
||||
return self.HttpResponse()
|
||||
|
||||
return super().form_valid(form)
|
||||
@@ -170,22 +171,22 @@ class EmployeeBonusPointNavView(views.HorillaNavView):
|
||||
data-target="#genericModal"
|
||||
"""
|
||||
|
||||
nav_title = _trans("Employee Bonus Point ")
|
||||
nav_title = _("Employee Bonus Point ")
|
||||
search_url = reverse_lazy("employee-bonus-point-list-view")
|
||||
search_swap_target = "#listContainer"
|
||||
group_by_fields = [
|
||||
("employee_id", _trans("Employee")),
|
||||
("employee_id", _("Employee")),
|
||||
(
|
||||
"employee_id__employee_work_info__reporting_manager_id",
|
||||
_trans("Reporting Manager"),
|
||||
_("Reporting Manager"),
|
||||
),
|
||||
("employee_id__employee_work_info__department_id", _trans("Department")),
|
||||
("employee_id__employee_work_info__job_position_id", _trans("Job Position")),
|
||||
("employee_id__employee_work_info__department_id", _("Department")),
|
||||
("employee_id__employee_work_info__job_position_id", _("Job Position")),
|
||||
(
|
||||
"employee_id__employee_work_info__employee_type_id",
|
||||
_trans("Employement Type"),
|
||||
_("Employement Type"),
|
||||
),
|
||||
("employee_id__employee_work_info__company_id", _trans("Company")),
|
||||
("employee_id__employee_work_info__company_id", _("Company")),
|
||||
]
|
||||
|
||||
|
||||
@@ -198,7 +199,7 @@ class EmployeeBonusPointFormView(views.HorillaFormView):
|
||||
|
||||
form_class = EmployeeBonusPointForm
|
||||
model = models.EmployeeBonusPoint
|
||||
new_display_title = _trans("Create Employee Bonus Point ")
|
||||
new_display_title = _("Create Employee Bonus Point ")
|
||||
# template_name = "bonus/bonus_form.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -220,7 +221,7 @@ class EmployeeBonusPointFormView(views.HorillaFormView):
|
||||
if form.instance.pk:
|
||||
message = "Bonus Point updated"
|
||||
form.save()
|
||||
messages.success(self.request, _trans(message))
|
||||
messages.success(self.request, _(message))
|
||||
return self.HttpResponse(
|
||||
"""
|
||||
<script>
|
||||
@@ -285,7 +286,7 @@ class FeedbackEmployeeFormView(views.HorillaFormView):
|
||||
|
||||
form_class = EmployeeFeedbackForm
|
||||
model = models.Feedback
|
||||
new_display_title = _trans("Share Feedback request ")
|
||||
new_display_title = _("Share Feedback request ")
|
||||
# template_name = "bonus/bonus_form.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -308,7 +309,7 @@ class FeedbackEmployeeFormView(views.HorillaFormView):
|
||||
)
|
||||
form.cleaned_data["others_id"] = other_employees
|
||||
form.save()
|
||||
messages.success(self.request, _trans(message))
|
||||
messages.success(self.request, _(message))
|
||||
return self.HttpResponse("<script>window.location.reload()</script>")
|
||||
return super().form_valid(form)
|
||||
|
||||
@@ -323,11 +324,20 @@ class BulkFeedbackFormView(views.HorillaFormView):
|
||||
form_class = BulkFeedbackForm
|
||||
model = models.Feedback
|
||||
view_id = "BulkFeedbackForm"
|
||||
new_display_title = _trans("Bulk Feedback request ")
|
||||
new_display_title = _("Bulk Feedback request ")
|
||||
template_name = "feedback/bulk_feedback_form.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
hints = {
|
||||
"Employee|Full name": "employee.get_full_name",
|
||||
"Employee|Email": "employee.get_mail",
|
||||
"Employee|Employee Type": "employee.get_employee_type",
|
||||
"Employee|Work Type": "employee.get_work_type",
|
||||
"Employee|Company": "employee.get_company",
|
||||
"Employee|Job position": "employee.get_job_position",
|
||||
}
|
||||
context["hints"] = hints
|
||||
return context
|
||||
|
||||
def form_invalid(self, form: Any) -> HttpResponse:
|
||||
@@ -348,8 +358,12 @@ class BulkFeedbackFormView(views.HorillaFormView):
|
||||
manager_id = (
|
||||
reporting_manager if cleaned_data["include_manager"] else None
|
||||
)
|
||||
title_template = cleaned_data["title"]
|
||||
temp = template.Template(title_template)
|
||||
title_context = template.Context({"employee": employee})
|
||||
render_title = temp.render(title_context)
|
||||
data = {
|
||||
"review_cycle": f"{cleaned_data['title']}-{employee} feedback",
|
||||
"review_cycle": render_title,
|
||||
"employee_id": employee,
|
||||
"manager_id": manager_id,
|
||||
"question_template_id": cleaned_data["question_template_id"],
|
||||
@@ -392,6 +406,6 @@ class BulkFeedbackFormView(views.HorillaFormView):
|
||||
feedback, cleaned_data["other_employees"]
|
||||
)
|
||||
feedback.others_id.add(*other_employees)
|
||||
messages.success(self.request, _trans(message))
|
||||
messages.success(self.request, _(message))
|
||||
return self.HttpResponse("<script>window.location.reload()</script>")
|
||||
return super().form_valid(form)
|
||||
|
||||
@@ -1288,6 +1288,7 @@ class BulkFeedbackForm(HorillaModelForm):
|
||||
)
|
||||
self.fields["status"].initial = "Not Started"
|
||||
self.fields["cyclic_feedback"].widget.attrs["onchange"] = "cyclicFeedback()"
|
||||
self.fields["title"].widget.attrs["autocomplete"] = "off"
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
|
||||
@@ -1,11 +1,134 @@
|
||||
{% load static %}
|
||||
<style>
|
||||
.note-hint-popover {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
width: 220px;
|
||||
background-color: white;
|
||||
border: 1px solid #ccc;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.note-popover-arrow {
|
||||
display: none;
|
||||
}
|
||||
.note-children-container {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.note-hint-item {
|
||||
padding: 6px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.note-hint-item.active,
|
||||
.note-hint-item:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
.note-hint-item.active {
|
||||
background-color: #d0e7ff; /* light blue */
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
{% include "generic/horilla_form.html" %}
|
||||
|
||||
<div class="note-popover bottom note-hint-popover" id="hint-popover">
|
||||
<div class="note-popover-arrow"></div>
|
||||
<div class="popover-content note-children-container" id="hint-content"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('#id_cyclic_feedback_period_parent_div').addClass('d-none')
|
||||
$('#id_cyclic_feedback_days_count_parent_div').addClass('d-none')
|
||||
})
|
||||
$(document).ready(function () {
|
||||
$('#id_cyclic_feedback_period_parent_div').addClass('d-none');
|
||||
$('#id_cyclic_feedback_days_count_parent_div').addClass('d-none');
|
||||
|
||||
let selectedIndex = -1;
|
||||
const input = document.querySelector('[name=title]');
|
||||
const popover = document.getElementById('hint-popover');
|
||||
const content = document.getElementById('hint-content');
|
||||
const suggestion = {{ hints|safe }};
|
||||
const hints = Object.keys(suggestion);
|
||||
|
||||
input.addEventListener('input', function (e) {
|
||||
const cursorPos = input.selectionStart;
|
||||
const value = input.value.slice(0, cursorPos);
|
||||
const match = value.match(/\{[^}]*$/);
|
||||
|
||||
if (match) {
|
||||
const query = match[0].slice(1); // after '{'
|
||||
const filtered = hints.filter(h => h.toLowerCase().includes(query.toLowerCase()));
|
||||
|
||||
if (filtered.length > 0) {
|
||||
selectedIndex = 0;
|
||||
renderHints(filtered, cursorPos);
|
||||
} else {
|
||||
popover.style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
popover.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener('keydown', function (e) {
|
||||
const items = content.querySelectorAll('.note-hint-item');
|
||||
if (!items.length || popover.style.display === 'none') return;
|
||||
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
selectedIndex = (selectedIndex + 1) % items.length;
|
||||
updateSelection(items);
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
selectedIndex = (selectedIndex - 1 + items.length) % items.length;
|
||||
updateSelection(items);
|
||||
} else if (e.key === 'Enter') {
|
||||
if (selectedIndex >= 0 && selectedIndex < items.length) {
|
||||
e.preventDefault();
|
||||
const selectedItem = items[selectedIndex];
|
||||
const word = suggestion[selectedItem.textContent];
|
||||
const cursorPos = input.selectionStart;
|
||||
const before = input.value.slice(0, cursorPos).replace(/\{[^}]*$/, '{'+'{' + word +'}'+'}');
|
||||
const after = input.value.slice(cursorPos);
|
||||
input.value = before + after;
|
||||
popover.style.display = 'none';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function renderHints(filtered, cursorPos) {
|
||||
content.innerHTML = filtered.map((h, i) =>
|
||||
`<div class="note-hint-item ${i === selectedIndex ? 'active' : ''}">${h}</div>`
|
||||
).join('');
|
||||
|
||||
const rect = input.getBoundingClientRect();
|
||||
popover.style.left = `${rect.left + window.scrollX}px`;
|
||||
popover.style.top = `${rect.bottom + window.scrollY}px`;
|
||||
popover.style.display = 'block';
|
||||
|
||||
content.querySelectorAll('.note-hint-item').forEach((item, i) => {
|
||||
item.addEventListener('mousedown', () => {
|
||||
const word = suggestion[item.textContent];
|
||||
const cursorPos = input.selectionStart;
|
||||
const before = input.value.slice(0, cursorPos).replace(/\{[^}]*$/, '{'+'{' + word +'}'+'}');
|
||||
const after = input.value.slice(cursorPos);
|
||||
input.value = before + after;
|
||||
popover.style.display = 'none';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function updateSelection(items) {
|
||||
items.forEach((item, i) => {
|
||||
item.classList.toggle('active', i === selectedIndex);
|
||||
if (i === selectedIndex) {
|
||||
item.scrollIntoView({ block: 'nearest' });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// this function is used to generate csrf token
|
||||
function getCookie(name) {
|
||||
let cookieValue = null;
|
||||
|
||||
Reference in New Issue
Block a user