[UPDT] PMS: Updated feedback with action button and easy filter

This commit is contained in:
Horilla
2023-10-26 12:56:03 +05:30
parent 6f09c0fff5
commit 58a9aba360
7 changed files with 493 additions and 29 deletions

View File

@@ -0,0 +1,244 @@
var archiveMessages = {
ar: "هل ترغب حقاً في أرشفة كل التعليقات المحددة؟",
de: "Möchten Sie wirklich alle ausgewählten Rückmeldungen archivieren?",
es: "¿Realmente quieres archivar todas las retroalimentaciones seleccionadas?",
en: "Do you really want to archive all the selected feedbacks?",
fr: "Voulez-vous vraiment archiver tous les retours sélectionnés?",
};
var unarchiveMessages = {
ar: "هل ترغب حقاً في إلغاء الأرشفة عن كل التعليقات المحددة؟",
de: "Möchten Sie wirklich alle ausgewählten Rückmeldungen aus der Archivierung nehmen?",
es: "¿Realmente quieres desarchivar todas las retroalimentaciones seleccionadas?",
en: "Do you really want to unarchive all the selected feedbacks?",
fr: "Voulez-vous vraiment désarchiver tous les retours sélectionnés?",
};
var deleteMessages = {
ar: "هل ترغب حقاً في حذف كل التعليقات المحددة؟",
de: "Möchten Sie wirklich alle ausgewählten Rückmeldungen löschen?",
es: "¿Realmente quieres eliminar todas las retroalimentaciones seleccionadas?",
en: "Do you really want to delete all the selected feedbacks?",
fr: "Voulez-vous vraiment supprimer tous les retours sélectionnés?",
};
var norowMessages = {
ar: "لم يتم تحديد أي صفوف.",
de: "Es wurden keine Zeilen ausgewählt.",
es: "No se han seleccionado filas.",
en: "No rows have been selected.",
fr: "Aucune ligne n'a été sélectionnée.",
};
$(".all-feedbacks").change(function (e) {
var is_checked = $(this).is(":checked");
if (is_checked) {
$(".all-feedback-row").prop("checked", true);
} else {
$(".all-feedback-row").prop("checked", false);
}
});
$(".self-feedbacks").change(function (e) {
var is_checked = $(this).is(":checked");
if (is_checked) {
$(".self-feedback-row").prop("checked", true);
} else {
$(".self-feedback-row").prop("checked", false);
}
});
$(".requested-feedbacks").change(function (e) {
var is_checked = $(this).is(":checked");
if (is_checked) {
$(".requested-feedback-row").prop("checked", true);
} else {
$(".requested-feedback-row").prop("checked", false);
}
});
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== "") {
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === name + "=") {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function getCurrentLanguageCode(callback) {
$.ajax({
type: "GET",
url: "/employee/get-language-code/",
success: function (response) {
var languageCode = response.language_code;
callback(languageCode); // Pass the language code to the callback
},
});
}
$("#archiveFeedback").click(function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
languageCode = code;
var confirmMessage = archiveMessages[languageCode];
var textMessage = norowMessages[languageCode];
var checkedRows = $(".feedback-checkbox").filter(":checked");
if (checkedRows.length === 0) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
e.preventDefault();
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
$.ajax({
type: "POST",
url: "/pms/feedback-bulk-archive?is_active=False",
data: {
csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids),
},
success: function (response, textStatus, jqXHR) {
if (jqXHR.status === 200) {
location.reload(); // Reload the current page
} else {
// console.log("Unexpected HTTP status:", jqXHR.status);
}
},
});
}
});
}
});
});
$("#unArchiveFeedback").click(function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
languageCode = code;
var confirmMessage = unarchiveMessages[languageCode];
var textMessage = norowMessages[languageCode];
var checkedRows = $(".feedback-checkbox").filter(":checked");
if (checkedRows.length === 0) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
e.preventDefault();
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
$.ajax({
type: "POST",
url: "/pms/feedback-bulk-archive?is_active=True",
data: {
csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids),
},
success: function (response, textStatus, jqXHR) {
if (jqXHR.status === 200) {
location.reload(); // Reload the current page
} else {
// console.log("Unexpected HTTP status:", jqXHR.status);
}
},
});
}
});
}
});
});
$("#deleteFeedback").click(function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
languageCode = code;
var confirmMessage = deleteMessages[languageCode];
var textMessage = norowMessages[languageCode];
var checkedRows = $(".feedback-checkbox").filter(":checked");
if (checkedRows.length === 0) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "error",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
e.preventDefault();
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
$.ajax({
type: "POST",
url: "/pms/feedback-bulk-delete",
data: {
csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids),
},
success: function (response, textStatus, jqXHR) {
if (jqXHR.status === 200) {
location.reload(); // Reload the current page
} else {
// console.log("Unexpected HTTP status:", jqXHR.status);
}
},
});
}
});
}
});
});

View File

@@ -84,10 +84,7 @@ $("#archiveObjectives").click(function (e) {
languageCode = code;
var confirmMessage = archiveMessages[languageCode];
var textMessage = norowMessages[languageCode];
var checkedRows = $(".all-objects-row").filter(":checked");
if (checkedRows.length === 0) {
var checkedRows = $(".own-objects-row").filter(":checked");
}
var checkedRows = $(".objective-checkbox").filter(":checked");
if (checkedRows.length === 0) {
Swal.fire({
text: textMessage,
@@ -139,10 +136,7 @@ $("#unArchiveObjectives").click(function (e) {
languageCode = code;
var confirmMessage = unarchiveMessages[languageCode];
var textMessage = norowMessages[languageCode];
var checkedRows = $(".all-objects-row").filter(":checked");
if (checkedRows.length === 0) {
var checkedRows = $(".own-objects-row").filter(":checked");
}
var checkedRows = $(".objective-checkbox").filter(":checked");
if (checkedRows.length === 0) {
Swal.fire({
text: textMessage,
@@ -194,10 +188,7 @@ $("#deleteObjectives").click(function (e) {
languageCode = code;
var confirmMessage = deleteMessages[languageCode];
var textMessage = norowMessages[languageCode];
var checkedRows = $(".all-objects-row").filter(":checked");
if (checkedRows.length === 0) {
var checkedRows = $(".own-objects-row").filter(":checked");
}
var checkedRows = $(".objective-checkbox").filter(":checked");
if (checkedRows.length === 0) {
Swal.fire({
text: textMessage,

View File

@@ -1,5 +1,6 @@
{% load i18n %}
{% load basefilters %}
{% load static %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
@@ -16,7 +17,30 @@
{% endif %}
{% include 'filter_tags.html' %}
<div class="oh-tabs">
<div class="d-flex flex-row-reverse">
<span class="m-3 review_ongoing" hx-get="{% url "feedback-list-search" %}?{{pd}}&status=At Risk" hx-target="#feedback_list" style="cursor: pointer">
<span class="oh-dot oh-dot--small me-1" style="background-color:red"></span>
{% trans "At Risk" %}
</span>
<span class="m-3 review_ongoing" hx-get="{% url "feedback-list-search" %}?{{pd}}&status=Not Started" hx-target="#feedback_list" style="cursor: pointer">
<span class="oh-dot oh-dot--small me-1" style="background-color:grey"></span>
{% trans "Not Started" %}
</span>
<span class="m-3 paid" hx-get="{% url "feedback-list-search" %}?{{pd}}&status=Behind" hx-target="#feedback_list" style="cursor: pointer">
<span class="oh-dot oh-dot--small me-1" style="background-color:orange"></span>
{% trans "Behind" %}
</span>
<span class="m-3 confirmed" hx-get="{% url "feedback-list-search" %}?{{pd}}&status=Closed" hx-target="#feedback_list" style="cursor: pointer">
<span class="oh-dot oh-dot--small me-1" style="background-color:rgb(103, 171, 238)"></span>
{% trans "Closed" %}
</span>
<span class="m-3 paid" hx-get="{% url "feedback-list-search" %}?{{pd}}&status=On Track" hx-target="#feedback_list" style="cursor: pointer">
<span class="oh-dot oh-dot--small me-1" style="background-color:yellowgreen"></span>
{% trans "On Track" %}
</span>
</div>
<div class="oh-tabs">
<ul class="oh-tabs__tablist">
<li class="oh-tabs__tab oh-tabs__tab" data-target="#tab_1">
{% trans "Self Feedback" %}
@@ -44,6 +68,14 @@
<div class="oh-sticky-table__table ">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th" style="width:10px;">
<input
type="checkbox"
class="self-feedbacks oh-input oh-input__checkbox"
id = "selfFeedback"
title='{% trans "Select All" %}'
/>
</div>
<div class="oh-sticky-table__th">{% trans "Employee" %}</div>
<div class="oh-sticky-table__th">{% trans "Title" %}</div>
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
@@ -54,12 +86,25 @@
<div class="oh-sticky-table__tbody">
{% for feedback in self_feedback.object_list %}
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__tr" draggable="true">
<div class="oh-sticky-table__sd {% if feedback.status == 'Closed' %}row-status--blue
{% elif feedback.status == 'On Track' %}row-status--yellow {% elif feedback.status == 'Not Started' %}row-status--gray
{% elif feedback.status == 'Behind' %}row-status--orange {% elif feedback.status == 'At Risk' %}row-status--red{% endif %}">
<div class="d-flex">
<div>
<input
type="checkbox"
id="{{feedback.id}}"
value="{{feedback.id}}"
class="oh-input feedback-checkbox oh-input__checkbox self-feedback-row ms-2"
/>
</div>
</div>
</div>
<a href="{% url 'feedback-detailed-view' id=feedback.id %}" style="color: inherit;text-decoration: none;" class="oh-sticky-table__sd">
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
<img src="https://ui-avatars.com/api/?name={{feedback.employee_id}}&background=random" class="oh-profile__image"
alt="{{feedback.employee_id}}" />
<img src="https://ui-avatars.com/api/?name={{feedback.employee_id}}&background=random" class="oh-profile__image"/>
</div>
<span class="oh-profile__name oh-text--dark">{{feedback.employee_id}}</span>
</div>
@@ -160,6 +205,14 @@
<div class="oh-sticky-table__table">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th" style="width:10px;">
<input
type="checkbox"
class="requested-feedbacks oh-input oh-input__checkbox"
id = "requestedFeedback"
title='{% trans "Select All" %}'
/>
</div>
<div class="oh-sticky-table__th">{% trans "Employee" %}</div>
<div class="oh-sticky-table__th">{% trans "Title" %}</div>
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
@@ -172,11 +225,24 @@
{% for feedback in requested_feedback.object_list %}
<div class="oh-sticky-table__tr" draggable="true">
<div class="oh-sticky-table__sd {% if feedback.status == 'Closed' %}row-status--blue
{% elif feedback.status == 'On Track' %}row-status--yellow {% elif feedback.status == 'Not Started' %}row-status--gray
{% elif feedback.status == 'Behind' %}row-status--orange {% elif feedback.status == 'At Risk' %}row-status--red{% endif %}">
<div class="d-flex">
<div>
<input
type="checkbox"
id="{{feedback.id}}"
value="{{feedback.id}}"
class="oh-input feedback-checkbox oh-input__checkbox requested-feedback-row ms-2"
/>
</div>
</div>
</div>
<a href="{% url 'feedback-detailed-view' id=feedback.id %}" style="color: inherit;text-decoration: none;" class="oh-sticky-table__sd">
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
<img src="https://ui-avatars.com/api/?name={{feedback.employee_id}}&background=random" class="oh-profile__image"
alt="Mary Magdalene" />
<img src="https://ui-avatars.com/api/?name={{feedback.employee_id}}&background=random" class="oh-profile__image"/>
</div>
<span class="oh-profile__name oh-text--dark">{{feedback.employee_id}}</span>
</div>
@@ -280,6 +346,14 @@
<div class="oh-sticky-table__table ">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th" style="width:10px;">
<input
type="checkbox"
class="all-feedbacks oh-input oh-input__checkbox"
id = "allFeedback"
title='{% trans "Select All" %}'
/>
</div>
<div class="oh-sticky-table__th">{% trans "Employee" %}</div>
<div class="oh-sticky-table__th">{% trans "Title" %}</div>
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
@@ -293,11 +367,24 @@
{% for feedback in all_feedbacks.object_list %}
<div class="oh-sticky-table__tr" draggable="true">
<div class="oh-sticky-table__sd {% if feedback.status == 'Closed' %}row-status--blue
{% elif feedback.status == 'On Track' %}row-status--yellow {% elif feedback.status == 'Not Started' %}row-status--gray
{% elif feedback.status == 'Behind' %}row-status--orange {% elif feedback.status == 'At Risk' %}row-status--red{% endif %}">
<div class="d-flex">
<div>
<input
type="checkbox"
id="{{feedback.id}}"
value="{{feedback.id}}"
class="oh-input feedback-checkbox oh-input__checkbox all-feedback-row ms-2"
/>
</div>
</div>
</div>
<a href="{% url 'feedback-detailed-view' id=feedback.id %}" style="color: inherit;text-decoration: none;" class="oh-sticky-table__sd">
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
<img src="https://ui-avatars.com/api/?name={{feedback.employee_id}}&background=random" class="oh-profile__image"
alt="Mary Magdalene" />
<img src="https://ui-avatars.com/api/?name={{feedback.employee_id}}&background=random" class="oh-profile__image"/>
</div>
<span class="oh-profile__name oh-text--dark">{{feedback.employee_id}}</span>
</div>
@@ -393,6 +480,8 @@
</div>
</div>
</div>
<script src="{% static 'src/feedback/action.js' %}"></script>
<script>
$(document).ready(function () {
@@ -417,6 +506,32 @@
});
$("#allFeedback").click(function (e) {
var is_checked = $(this).is(":checked");
if (is_checked) {
$(".all-feedback-row").prop("checked", true);
} else {
$(".own-feedback-row").prop("checked", false);
}
});
$("#requestedFeedback").click(function (e) {
var is_checked = $(this).is(":checked");
if (is_checked) {
$(".requested-feedback-row").prop("checked", true);
} else {
$(".requested-feedback-row").prop("checked", false);
}
});
$("#selfFeedback").click(function (e) {
var is_checked = $(this).is(":checked");
if (is_checked) {
$(".self-feedback-row").prop("checked", true);
} else {
$(".self-feedback-row").prop("checked", false);
}
});
});
</script>

View File

@@ -146,6 +146,51 @@
</form>
</div>
</div>
<div class="oh-btn-group ml-2">
<div class="oh-dropdown" x-data="{open: false}">
<button
class="oh-btn oh-btn--dropdown oh-btn oh-btn--shadow"
@click="open = !open"
@click.outside="open = false"
>
{% trans "Actions" %}
</button>
<div class="oh-dropdown__menu oh-dropdown__menu--right" x-show="open"
style="display: none;"
>
<ul class="oh-dropdown__items">
<li class="oh-dropdown__item">
<a href="#" class="oh-dropdown__link " id="archiveFeedback"
>{% trans "Archive" %}</a
>
</li>
<li class="oh-dropdown__item">
<a href="#" class="oh-dropdown__link "
id="unArchiveFeedback"
>{% trans "Un-Archive" %}</a
>
</li>
{% if perms.pms.delete_feedback %}
<li class="oh-dropdown__item">
<a
href="#"
class="oh-dropdown__link oh-dropdown__link--danger"
id="deleteFeedback"
>{% trans "Delete" %}</a
>
</li>
{% endif %}
</ul>
</div>
</div>
</div>
<!-- checking user permission for objective creation -->
{% if perms.pms.view_questiontemplate or request.user|filtersubordinates %}
<div class="oh-btn-group ml-2">
@@ -153,7 +198,6 @@
<a href="{% url 'feedback-creation' %}" class="oh-btn oh-btn--secondary" role="button">
<ion-icon class="me-2 md hydrated" name="add-outline" role="img" aria-label="add outline"></ion-icon>
{% trans "Create" %}</a>
</div>
</div>
{% endif %}
@@ -168,6 +212,7 @@
</div>
</main>
<script src="{% static 'src/feedback/action.js' %}"></script>
<script src="{% static '/base/filter.js' %}"></script>
<script>

View File

@@ -67,14 +67,16 @@
<div class="oh-sticky-table__tbody">
{% for own_objective in own_objectives.object_list %}
<div class="oh-sticky-table__tr" draggable="true">
<div class="oh-sticky-table__sd {% if own_objective.status == 'Closed' %}row-status--blue {% elif own_objective.status == 'On Track' %}row-status--yellow {% elif own_objective.status == 'Not Started' %}row-status--gray {% elif own_objective.status == 'Behind' %}row-status--orange {% elif own_objective.status == 'At Risk' %}row-status--red{% endif %}">
<div class="oh-sticky-table__sd {% if own_objective.status == 'Closed' %}row-status--blue
{% elif own_objective.status == 'On Track' %}row-status--yellow {% elif own_objective.status == 'Not Started' %}row-status--gray
{% elif own_objective.status == 'Behind' %}row-status--orange {% elif own_objective.status == 'At Risk' %}row-status--red{% endif %}">
<div class="d-flex">
<div>
<input
type="checkbox"
id="{{own_objective.id}}"
value="{{own_objective.id}}"
class="oh-input payslip-checkbox oh-input__checkbox own-objects-row ms-2"
class="oh-input objective-checkbox oh-input__checkbox own-objects-row ms-2"
/>
</div>
</div>
@@ -282,14 +284,16 @@
<div class="oh-sticky-table__tbody">
{% for all_objective in all_objectives.object_list %}
<div class="oh-sticky-table__tr" draggable="true">
<div class="oh-sticky-table__sd {% if all_objective.status == 'Closed' %}row-status--blue {% elif all_objective.status == 'On Track' %}row-status--yellow {% elif all_objective.status == 'Not Started' %}row-status--gray {% elif all_objective.status == 'Behind' %}row-status--orange {% elif all_objective.status == 'At Risk' %}row-status--red{% endif %}">
<div class="oh-sticky-table__sd {% if all_objective.status == 'Closed' %}row-status--blue
{% elif all_objective.status == 'On Track' %}row-status--yellow {% elif all_objective.status == 'Not Started' %}row-status--gray
{% elif all_objective.status == 'Behind' %}row-status--orange {% elif all_objective.status == 'At Risk' %}row-status--red{% endif %}">
<div class="d-flex">
<div>
<input
type="checkbox"
id="{{all_objective.id}}"
value="{{all_objective.id}}"
class="oh-input payslip-checkbox oh-input__checkbox all-objects-row ms-2"
class="oh-input objective-checkbox oh-input__checkbox all-objects-row ms-2"
/>
</div>
</div>

View File

@@ -182,4 +182,14 @@ urlpatterns = [
views.objective_bulk_delete,
name="objective-bulk-delete",
),
path(
"feedback-bulk-archive",
views.feedback_bulk_archive,
name="feedback-bulk-archive",
),
path(
"feedback-bulk-delete",
views.feedback_bulk_delete,
name="feedback-bulk-delete",
),
]

View File

@@ -1285,10 +1285,10 @@ def feedback_delete(request, id):
else:
messages.warning(
request,
_("Feedback %(review_cycle)s is ongoing you you can archive it!")
% {"review_cycle": feedback.review_cycle},
_("You can't delete feedback %(review_cycle)s with status %(status)s")
% {"review_cycle": feedback.review_cycle, "status": feedback.status},
)
return redirect(feedback_detailed_view, feedback.id)
return redirect(feedback_list_view)
except Feedback.DoesNotExist:
messages.error(request, _("Feedback not found."))
@@ -1966,3 +1966,58 @@ def objective_bulk_delete(request):
messages.error(request, _("Objective not found."))
return JsonResponse({"message": "Success"})
@login_required
def feedback_bulk_archive(request):
"""
This method is used to archive/un-archive bulk feedbacks
"""
ids = request.POST["ids"]
ids = json.loads(ids)
is_active = False
message = _("un-archived")
if request.GET.get("is_active") == "False":
is_active = True
message = _("archived")
for feedback_id in ids:
feedback_id = Feedback.objects.get(id=feedback_id)
feedback_id.archive = is_active
feedback_id.save()
messages.success(
request,
_("{feedback} is {message}").format(
feedback=feedback_id, message=message
),
)
return JsonResponse({"message": "Success"})
@login_required
@manager_can_enter(perm="pms.delete_feedback")
def feedback_bulk_delete(request):
"""
This method is used to bulk delete feedbacks
"""
ids = request.POST["ids"]
ids = json.loads(ids)
for feedback_id in ids:
try:
feedback = Feedback.objects.get(id=feedback_id)
if feedback.status == "Closed" or feedback.status == "Not Started":
feedback.delete()
messages.success(
request,
_("Feedback %(review_cycle)s deleted successfully!")
% {"review_cycle": feedback.review_cycle},
)
else:
messages.warning(
request,
_("You can't delete feedback %(review_cycle)s with status %(status)s")
% {"review_cycle": feedback.review_cycle, "status": feedback.status},
)
except Feedback.DoesNotExist:
messages.error(request, _("Feedback not found."))
return JsonResponse({"message": "Success"})