[UPDT] RECRUITMENT: Added confirmation to candidate stage change

This commit is contained in:
Horilla
2024-08-08 11:43:15 +05:30
parent 9915e1bd96
commit d277268126
6 changed files with 178 additions and 95 deletions

View File

@@ -207,24 +207,22 @@
</div>
{% endif %}
<div onclick="event.stopPropagation()" class="oh-sticky-table__td oh-table-config__td">
<select
name="stage_id"
onchange="
preStageId= {{stage.id}}
stageId = this.value
canId={{cand.id}}
updateCandStage(canId,stageId,preStageId)"
id="stageChange{{cand.id}}"
class="oh-select w-100"
data-candidate-id="{{cand.id}}" data-stage-id="{{stage.id}}">
{% for sg in rec.ordered_stages %}
<option value="{{sg.id}}" {% if sg == cand.stage_id %} selected{% endif %}>{{sg}}</option>
{% endfor %}
</select>
<input onclick="setTimeout(() => {
$('#stageReloadContainer{{rec.id}}').click()
}, 100);" type="submit" hidden>
<select
name="stage_id"
onchange="checkSequence(this)"
data-stage_id = {{stage.id}}
data-cand_id = {{cand.id}}
data-stage_order = '{{rec.ordered_stages|to_json|safe}}'
id="stageChange{{cand.id}}"
class="oh-select w-100"
data-candidate-id="{{cand.id}}" data-stage-id="{{stage.id}}">
{% for sg in rec.ordered_stages %}
<option value="{{sg.id}}" {% if sg == cand.stage_id %} selected{% endif %}>{{sg}}</option>
{% endfor %}
</select>
<input onclick="setTimeout(() => {
$('#stageReloadContainer{{rec.id}}').click()
}, 100);" type="submit" hidden>
</div>
<div onclick="event.stopPropagation()" class="oh-sticky-table__td oh-table-config__td">

View File

@@ -8,6 +8,8 @@
style="cursor: pointer;overflow: visible;"
data-candidate = "{{cand.name}}"
data-job-position ="{{cand.job_position_id}}"
data-pre_stage_id ="{{cand.stage_id.id}}"
data-stage_order = '{{cand.recruitment_id.ordered_stages|to_json|safe}}'
onclick="window.location.href = `{% url 'candidate-view-individual' cand.id %}`"
>
<div class="oh-kanban__card-head align-items-baseline pb-0" {% if cand.is_offer_rejected %}

View File

@@ -409,103 +409,98 @@
toast.addEventListener("mouseleave", Swal.resumeTimer);
},
});
function isNextStage(currentStageId, targetStageId, parsedStageOrder) {
var currentStageIndex = parsedStageOrder.findIndex(stage => stage.id == currentStageId);
var targetStageIndex = parsedStageOrder.findIndex(stage => stage.id == targetStageId);
return targetStageIndex === currentStageIndex + 1 || currentStageIndex === targetStageIndex ;
}
htmx.onLoad(function (content) {
var sortables = content.querySelectorAll(".hx-sortable");
for (var i = 0; i < sortables.length; i++) {
var sortable = sortables[i];
window.candidateCurrentStage = undefined;
$(sortable).droppable({
drop: function (event, ui) {
stageId = $(this)
.closest(".candidate-table")
.attr("data-stage-id");
row = $(ui.draggable);
candidateId = row.attr("data-candidate-id");
currentStage = row.find('[name="stage_id"]').val();
if (stageId != window.candidateCurrentStage) {
array = $(this).find(
"input[type=text][name=order]:hidden"
);
values = [];
setTimeout(function () {
for (
let index = 0;
index < array.length;
index++
) {
values.push($(array[index]).val());
}
$.ajax({
type: "get",
url: "{% url 'update-candidate-stage-and-sequence' %}",
data: {
stage_id: stageId,
candidate_id: candidateId,
order: values,
},
success: function (response) {
row.find('[name="stage_id"]').val(
stageId
);
Toast.fire({
icon: "success",
title: '{% trans "Sequence updated" %}',
position: "top-end",
});
if (response.message) {
Swal.fire({
title: response.message,
text: `Total vacancy is ${response.vacancy}.`,
icon: "info",
confirmButtonText: "Ok",
});
}
},
error: function (xhr, status, error) {
Toast.fire({
icon: "error",
title: '{% trans "Something went wrong" %}',
position: "top-end",
});
},
});
}, 100);
}
},
});
$(sortable).sortable({
connectWith: ".hx-sortable",
animation: 150,
ghostClass: "blue-background-class",
items: "> :not(.htmx-indicator)",
start: function (event, ui) {
row = $(ui.item);
candidateCurrentStage = row
.closest(".candidate-table")
.attr("data-stage-id");
var row = $(ui.item);
window.candidateCurrentStage = row.closest(".candidate-table").attr("data-stage-id");
},
stop: function (event, ui) {
var row = $(ui.item);
var candidateId = row.attr("data-candidate-id");
var currentStageId = parseInt($(this).closest(".candidate-table").attr("data-stage-id"));
var targetStageId = parseInt(row.find('[name="stage_id"]').val());
var stageOrderJson = row.attr("data-stage_order");
if (stageOrderJson) {
var parsedStageOrder = JSON.parse(stageOrderJson);
var preStageId = row.attr("data-pre_stage_id");
var preStage = parsedStageOrder.find(stage => stage.id == preStageId);
var stageOrder = parsedStageOrder.map(stage => stage.id);
if (!isNextStage(currentStageId, targetStageId, parsedStageOrder)) {
if (sessionStorage.getItem('showRecuitmentKanbanConfirmation') !== 'false') {
Swal.fire({
title: "Confirm Stage Change",
text: "The candidate is not being moved to the next stage. Do you want to proceed?",
html: `
<p>The candidate is not being moved to the next stage. Do you want to proceed?</p>
<label><input type="checkbox" id="doNotShowAgain"> Don't show this again in this session</label>
`,
icon: "warning",
showCancelButton: true,
cancelButtonColor: "#d33",
confirmButtonColor: "#008000",
confirmButtonText: "Confirm",
preConfirm: () => {
const doNotShowAgain = Swal.getPopup().querySelector('#doNotShowAgain').checked;
if (doNotShowAgain) {
sessionStorage.setItem('showRecuitmentKanbanConfirmation', 'false');
}
}
}).then((result) => {
if (result.isConfirmed) {
handleValidDrop(targetStageId, candidateId, row, sortable);
} else {
$(sortable).sortable('cancel');
}
});
} else {
handleValidDrop(targetStageId, candidateId, row, sortable);
}
} else {
handleValidDrop(targetStageId, candidateId, row, sortable);
}
} else {
handleValidDrop(targetStageId, candidateId, row, sortable);
}
},
update: function (event, ui) {
array = $(this).find(
"input[type=text][name=order]:hidden"
);
stageSelect = $(ui.item).find("[name=stage_id]");
stageId = $(this).attr("data-stage-id");
parent = $(this).parent();
var array = $(this).find("input[type=text][name=order]:hidden");
var stageSelect = $(ui.item).find("[name=stage_id]");
var stageId = $(this).attr("data-stage-id");
var parent = $(this).parent();
if (stageId != stageSelect.val()) {
stageSelect.val(stageId);
stageTitle = $(
`[name=stage_id] option[value=${stageId}]:first`
).html();
stageSelect
.next()
.find(".select2-selection__rendered")
.html(stageTitle);
var stageTitle = $(`[name=stage_id] option[value=${stageId}]:first`).html();
stageSelect.next().find(".select2-selection__rendered").html(stageTitle);
}
values = [];
var values = [];
for (let index = 0; index < array.length; index++) {
values.push($(array[index]).val());
}
$.ajax({
type: "get",
url: "{% url 'update-candidate-sequence' %}",
@@ -523,7 +518,52 @@
});
}
});
function handleValidDrop(stageId, candidateId, row, sortable) {
if (stageId != window.candidateCurrentStage) {
var array = $(sortable).find("input[type=text][name=order]:hidden");
var values = [];
setTimeout(function () {
for (let index = 0; index < array.length; index++) {
values.push($(array[index]).val());
}
$.ajax({
type: "get",
url: "{% url 'update-candidate-stage-and-sequence' %}",
data: {
stage_id: stageId,
candidate_id: candidateId,
order: values,
},
success: function (response) {
row.find('[name="stage_id"]').val(stageId);
Toast.fire({
icon: "success",
title: '{% trans "Sequence updated" %}',
position: "top-end",
});
if (response.message) {
Swal.fire({
title: response.message,
text: `Total vacancy is ${response.vacancy}.`,
icon: "info",
confirmButtonText: "Ok",
});
}
},
error: function (xhr, status, error) {
Toast.fire({
icon: "error",
title: '{% trans "Something went wrong" %}',
position: "top-end",
});
},
});
}, 100);
}
}
});
$(document).on("htmx:beforeRequest", function (event) {
var target = event.target;

View File

@@ -5,6 +5,7 @@ This module is used to write custom template filters.
"""
import json
import uuid
from django import template
@@ -155,3 +156,11 @@ def pipeline_grouper(grouper: dict = {}):
This method is used itemize the dictionary
"""
return grouper["title"], grouper["stages"]
@register.filter(name="to_json")
def to_json(value):
ordered_list = [
{"id": val.id, "stage": val.stage, "type": val.stage_type} for val in value
]
return json.dumps(ordered_list)

View File

@@ -825,6 +825,9 @@ def candidate_stage_update(request, cand_id):
Args:
id : candidate_id
"""
print(
"heloooooooooooooooooooooooooooooooooooooooooooooooooo000000000000000000000000000000000000000000000000000000000000000000000000000000000"
)
stage_id = request.POST["stageId"]
candidate_obj = Candidate.objects.get(id=cand_id)
history_queryset = candidate_obj.history_set.all().first()

View File

@@ -679,6 +679,37 @@
},
});
}
function checkSequence(element) {
var preStageId = $(element).data("stage_id")
var canIds = $(element).data("cand_id")
var stageOrderJson = $(element).attr("data-stage_order")
var stageId = $(element).val()
var parsedStageOrder = JSON.parse(stageOrderJson);
var stage = parsedStageOrder.find(stage => stage.id == stageId);
var preStage = parsedStageOrder.find(stage => stage.id == preStageId);
var stageOrder = parsedStageOrder.map(stage => stage.id);
if (stageOrder.indexOf(parseInt(stageId)) != stageOrder.indexOf(parseInt(preStageId)) + 1 && stage.type != "cancelled" ) {
Swal.fire({
title: "Confirm",
text: `Are you sure to change the candidate from ${preStage.stage} stage to ${stage.stage} stage`,
icon: 'info',
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
updateCandStage(canIds,stageId,preStageId)
}
});
}
else {
updateCandStage(canIds,stageId,preStageId)
}
}
</script>
<script>
// Switch General Tab