[UPDT] RECRUITMENT: Added confirmation to candidate stage change
This commit is contained in:
@@ -207,14 +207,12 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div onclick="event.stopPropagation()" class="oh-sticky-table__td oh-table-config__td">
|
<div onclick="event.stopPropagation()" class="oh-sticky-table__td oh-table-config__td">
|
||||||
|
|
||||||
<select
|
<select
|
||||||
name="stage_id"
|
name="stage_id"
|
||||||
onchange="
|
onchange="checkSequence(this)"
|
||||||
preStageId= {{stage.id}}
|
data-stage_id = {{stage.id}}
|
||||||
stageId = this.value
|
data-cand_id = {{cand.id}}
|
||||||
canId={{cand.id}}
|
data-stage_order = '{{rec.ordered_stages|to_json|safe}}'
|
||||||
updateCandStage(canId,stageId,preStageId)"
|
|
||||||
id="stageChange{{cand.id}}"
|
id="stageChange{{cand.id}}"
|
||||||
class="oh-select w-100"
|
class="oh-select w-100"
|
||||||
data-candidate-id="{{cand.id}}" data-stage-id="{{stage.id}}">
|
data-candidate-id="{{cand.id}}" data-stage-id="{{stage.id}}">
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
style="cursor: pointer;overflow: visible;"
|
style="cursor: pointer;overflow: visible;"
|
||||||
data-candidate = "{{cand.name}}"
|
data-candidate = "{{cand.name}}"
|
||||||
data-job-position ="{{cand.job_position_id}}"
|
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 %}`"
|
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 %}
|
<div class="oh-kanban__card-head align-items-baseline pb-0" {% if cand.is_offer_rejected %}
|
||||||
|
|||||||
@@ -409,31 +409,122 @@
|
|||||||
toast.addEventListener("mouseleave", Swal.resumeTimer);
|
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) {
|
htmx.onLoad(function (content) {
|
||||||
var sortables = content.querySelectorAll(".hx-sortable");
|
var sortables = content.querySelectorAll(".hx-sortable");
|
||||||
|
|
||||||
for (var i = 0; i < sortables.length; i++) {
|
for (var i = 0; i < sortables.length; i++) {
|
||||||
var sortable = sortables[i];
|
var sortable = sortables[i];
|
||||||
window.candidateCurrentStage = undefined;
|
window.candidateCurrentStage = undefined;
|
||||||
$(sortable).droppable({
|
|
||||||
drop: function (event, ui) {
|
$(sortable).sortable({
|
||||||
stageId = $(this)
|
connectWith: ".hx-sortable",
|
||||||
.closest(".candidate-table")
|
animation: 150,
|
||||||
.attr("data-stage-id");
|
ghostClass: "blue-background-class",
|
||||||
row = $(ui.draggable);
|
items: "> :not(.htmx-indicator)",
|
||||||
candidateId = row.attr("data-candidate-id");
|
start: function (event, ui) {
|
||||||
currentStage = row.find('[name="stage_id"]').val();
|
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) {
|
||||||
|
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);
|
||||||
|
var stageTitle = $(`[name=stage_id] option[value=${stageId}]:first`).html();
|
||||||
|
stageSelect.next().find(".select2-selection__rendered").html(stageTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = [];
|
||||||
|
for (let index = 0; index < array.length; index++) {
|
||||||
|
values.push($(array[index]).val());
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "get",
|
||||||
|
url: "{% url 'update-candidate-sequence' %}",
|
||||||
|
traditional: true,
|
||||||
|
data: {
|
||||||
|
order: values,
|
||||||
|
stage_id: stageId,
|
||||||
|
},
|
||||||
|
success: function (response) {
|
||||||
|
$(`.reload-badge`).click();
|
||||||
|
$(`.stage-badges`).removeAttr("title");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleValidDrop(stageId, candidateId, row, sortable) {
|
||||||
if (stageId != window.candidateCurrentStage) {
|
if (stageId != window.candidateCurrentStage) {
|
||||||
array = $(this).find(
|
var array = $(sortable).find("input[type=text][name=order]:hidden");
|
||||||
"input[type=text][name=order]:hidden"
|
var values = [];
|
||||||
);
|
|
||||||
values = [];
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
for (
|
for (let index = 0; index < array.length; index++) {
|
||||||
let index = 0;
|
|
||||||
index < array.length;
|
|
||||||
index++
|
|
||||||
) {
|
|
||||||
values.push($(array[index]).val());
|
values.push($(array[index]).val());
|
||||||
}
|
}
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -445,9 +536,7 @@
|
|||||||
order: values,
|
order: values,
|
||||||
},
|
},
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
row.find('[name="stage_id"]').val(
|
row.find('[name="stage_id"]').val(stageId);
|
||||||
stageId
|
|
||||||
);
|
|
||||||
Toast.fire({
|
Toast.fire({
|
||||||
icon: "success",
|
icon: "success",
|
||||||
title: '{% trans "Sequence updated" %}',
|
title: '{% trans "Sequence updated" %}',
|
||||||
@@ -472,58 +561,9 @@
|
|||||||
});
|
});
|
||||||
}, 100);
|
}, 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");
|
|
||||||
},
|
|
||||||
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();
|
|
||||||
if (stageId != stageSelect.val()) {
|
|
||||||
stageSelect.val(stageId);
|
|
||||||
stageTitle = $(
|
|
||||||
`[name=stage_id] option[value=${stageId}]:first`
|
|
||||||
).html();
|
|
||||||
stageSelect
|
|
||||||
.next()
|
|
||||||
.find(".select2-selection__rendered")
|
|
||||||
.html(stageTitle);
|
|
||||||
}
|
|
||||||
values = [];
|
|
||||||
for (let index = 0; index < array.length; index++) {
|
|
||||||
values.push($(array[index]).val());
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
type: "get",
|
|
||||||
url: "{% url 'update-candidate-sequence' %}",
|
|
||||||
traditional: true,
|
|
||||||
data: {
|
|
||||||
order: values,
|
|
||||||
stage_id: stageId,
|
|
||||||
},
|
|
||||||
success: function (response) {
|
|
||||||
$(`.reload-badge`).click();
|
|
||||||
$(`.stage-badges`).removeAttr("title");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
$(document).on("htmx:beforeRequest", function (event) {
|
$(document).on("htmx:beforeRequest", function (event) {
|
||||||
var target = event.target;
|
var target = event.target;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ This module is used to write custom template filters.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
@@ -155,3 +156,11 @@ def pipeline_grouper(grouper: dict = {}):
|
|||||||
This method is used itemize the dictionary
|
This method is used itemize the dictionary
|
||||||
"""
|
"""
|
||||||
return grouper["title"], grouper["stages"]
|
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)
|
||||||
|
|||||||
@@ -825,6 +825,9 @@ def candidate_stage_update(request, cand_id):
|
|||||||
Args:
|
Args:
|
||||||
id : candidate_id
|
id : candidate_id
|
||||||
"""
|
"""
|
||||||
|
print(
|
||||||
|
"heloooooooooooooooooooooooooooooooooooooooooooooooooo000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
)
|
||||||
stage_id = request.POST["stageId"]
|
stage_id = request.POST["stageId"]
|
||||||
candidate_obj = Candidate.objects.get(id=cand_id)
|
candidate_obj = Candidate.objects.get(id=cand_id)
|
||||||
history_queryset = candidate_obj.history_set.all().first()
|
history_queryset = candidate_obj.history_set.all().first()
|
||||||
|
|||||||
@@ -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>
|
||||||
<script>
|
<script>
|
||||||
// Switch General Tab
|
// Switch General Tab
|
||||||
|
|||||||
Reference in New Issue
Block a user