[ADD] HORILLA_THEME: Added new style for the select and filter section for generic form…
This commit is contained in:
@@ -1,107 +1,172 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% include "generic/components.html" %}
|
||||
{% comment %} {% include "generic/components.html" %} {% endcomment %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% now "Y-m-d" as today %}
|
||||
|
||||
<div id="interview">
|
||||
{% if candidate.candidate_interview.exists %}
|
||||
<div class="flex items-center justify-between mt-4">
|
||||
<span class="font-semibold text-sm">
|
||||
{{ candidate }}'s {% trans "Scheduled Interviews" %}
|
||||
</span>
|
||||
{% if candidate.candidate_interview.exists %}
|
||||
<div class="flex items-center justify-between mt-4">
|
||||
<span class="font-semibold text-sm">
|
||||
{{ candidate }}'s {% trans "Scheduled Interviews" %}
|
||||
</span>
|
||||
|
||||
<button type="button"
|
||||
hx-get="{% url 'interview-schedule' candidate.id %}"
|
||||
title="{% trans 'Schedule Interview' %}"
|
||||
hx-target="#genericModalBody"
|
||||
hx-swap="innerHTML"
|
||||
data-target="#genericModal"
|
||||
class="oh-btn oh-btn--secondary flex items-center gap-1 text-sm"
|
||||
data-toggle="oh-modal-toggle">
|
||||
<ion-icon name="add" class="text-base" role="img" aria-label="add"></ion-icon>
|
||||
{% trans "Add" %}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ol class="oh-activity-sidebar__qa-list" role="list">
|
||||
{% for interview_schedule in candidate.candidate_interview.all %}
|
||||
<li class="oh-activity-sidebar__qa-item">
|
||||
<span class="oh-activity-sidebar__q" style="font-size:16px;">
|
||||
<span class="float-end" title="{% trans "Delete" %}" hx-get="{% url 'delete-interview' interview_schedule.id %}?view=false"
|
||||
data-target="#activitySidebar"
|
||||
hx-swap="innerHTML" hx-target="#interview">
|
||||
<ion-icon name="close-outline" style="font-size: 24px" role="img" class="md hydrated"
|
||||
aria-label="close outline"></ion-icon>
|
||||
</span>
|
||||
<span class="float-end" title="{% trans "Edit" %}" hx-get="{% url 'edit-interview' interview_schedule.id %}?view=false"
|
||||
data-target="#genericModal" hx-swap="innerHTML" hx-target="#genericModalBody"
|
||||
data-toggle="oh-modal-toggle">
|
||||
<ion-icon name="create-outline" style="font-size: 19px" role="img" class="md hydrated"
|
||||
aria-label="create outline"></ion-icon>
|
||||
</span>
|
||||
{{forloop.counter}}.<span class="ms-1 mb-2"> {% trans "Date" %} :</span> <span class="ms-2 dateformat_changer">{{ interview_schedule.interview_date }}</span>
|
||||
<span class="d-flex ms-3 mb-2 mt-2">{% trans "Time" %} : <span class=" ms-2 timeformat_changer">{{ interview_schedule.interview_time }}</span></span>
|
||||
<span class="ms-3">{% trans "Interviewer" %} :</span>
|
||||
{% for interviewer in interview_schedule.employee_id.all %}
|
||||
 <i id="fabIcon" style="font-size:12px;" class="material-icons">radio_button_checked</i> {{ interviewer }}
|
||||
{% endfor %}
|
||||
<br>
|
||||
{% if interview_schedule.description %}
|
||||
<span class="d-flex ms-3 mb-2 mt-2">{% trans "Description" %} : <span class=" ms-2">{{ interview_schedule.description }}</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if interview_schedule.completed %}
|
||||
<div class="d-flex" style="color:green;">
|
||||
<i id="fabIcon" style="font-size:18px;" class="material-icons ms-3 mt-2">check_circle</i>
|
||||
<span class="oh-activity-sidebar__q mt-2">{% trans "Interview Completed" %}</span>
|
||||
</div>
|
||||
{% elif interview_schedule.interview_date|date:"Y-m-d" < now|date:"Y-m-d" %}
|
||||
<div class="d-flex" style="color:red;">
|
||||
<i id="fabIcon" style="font-size:18px" class="material-icons ms-3 mt-2">dangerous</i>
|
||||
<span class="oh-activity-sidebar__q mt-2">{% trans "Expired Interview" %}</span>
|
||||
</div>
|
||||
{% elif interview_schedule.interview_date|date:"Y-m-d" > now|date:"Y-m-d" %}
|
||||
<div class="d-flex" style="color:orange;">
|
||||
<i id="fabIcon" title="{{interview_schedule.interview_date|timeuntil}}" style="font-size:18px;" class="material-icons ms-3 mt-2">schedule</i>
|
||||
<span class="oh-activity-sidebar__q mt-2">{% trans "Upcoming Interview" %}</span>
|
||||
</div>
|
||||
{% elif interview_schedule.interview_date|date:"Y-m-d" == now|date:"Y-m-d" and not interview_schedule.completed %}
|
||||
<div class="d-flex" style="color:blue;">
|
||||
<i id="fabIcon" style="font-size:18px;" class="material-symbols-outlined ms-3 mt-2">today</i>
|
||||
<span class="oh-activity-sidebar__q mt-2">{% trans "Interview Today" %}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</li>
|
||||
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% else %}
|
||||
<div class="flex items-center justify-between mt-4">
|
||||
<span class="font-semibold text-sm">
|
||||
{{ candidate }}'s {% trans "Scheduled Interviews" %}
|
||||
</span>
|
||||
|
||||
<button type="button"
|
||||
hx-get="{% url 'interview-schedule' candidate.id %}"
|
||||
title="{% trans 'Schedule Interview' %}"
|
||||
hx-target="#genericModalBody"
|
||||
hx-swap="innerHTML"
|
||||
data-target="#genericModal"
|
||||
class="oh-btn oh-btn--secondary flex items-center gap-1 text-sm"
|
||||
data-toggle="oh-modal-toggle">
|
||||
<ion-icon name="add" class="text-base" role="img" aria-label="add"></ion-icon>
|
||||
{% trans "Add" %}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="oh-wrapper h-full" align="center">
|
||||
<div class="xl:col-span-4 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card h-[70%]">
|
||||
<div class="flex flex-col items-center justify-center h-full">
|
||||
<img src="/static/horilla_theme/assets/img/no-records.svg" alt="" width="300" class="mb-4">
|
||||
<p class="text-[#666] mb-5">{% trans "No interviews are scheduled for this candidate." %}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<button
|
||||
type="button"
|
||||
hx-get="{% url 'interview-schedule' candidate.id %}"
|
||||
title="{% trans 'Schedule Interview' %}"
|
||||
hx-target="#genericModalBody"
|
||||
hx-swap="innerHTML"
|
||||
data-target="#genericModal"
|
||||
class="oh-btn oh-btn--secondary flex items-center gap-1 text-sm"
|
||||
data-toggle="oh-modal-toggle"
|
||||
>
|
||||
<ion-icon
|
||||
name="add"
|
||||
class="text-base"
|
||||
role="img"
|
||||
aria-label="add"
|
||||
></ion-icon>
|
||||
{% trans "Add" %}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ol class="mt-4" role="list">
|
||||
{% for interview_schedule in candidate.candidate_interview.all %}
|
||||
|
||||
<li class="mx-auto mb-3 list-none bg-white rounded-2xl overflow-hidden shadow-md border border-slate-200 hover:bg-slate-50 transition-all duration-200" >
|
||||
<div class="grid grid-cols-1 md:grid-cols-[auto_1fr_auto_auto] gap-6 items-center p-5 ">
|
||||
<div class="bg-slate-100 text-slate-600 w-10 h-10 rounded-full flex items-center justify-center font-semibold">
|
||||
{{forloop.counter}}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1 flex-wrap gap-4">
|
||||
|
||||
<div class="flex flex-col gap-1 basis-28 shrink-0">
|
||||
<label class="text-[0.7rem] text-slate-500 font-semibold uppercase tracking-wider">{% trans "Date" %}</label>
|
||||
<span class="text-[0.9rem] text-slate-800 font-medium dateformat_changer">{{ interview_schedule.interview_date }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1 basis-24 shrink-0">
|
||||
<label class="text-[0.7rem] text-slate-500 font-semibold uppercase tracking-wider">{% trans "Time" %}</label>
|
||||
<span class="text-[0.9rem] text-slate-800 font-medium timeformat_changer">{{ interview_schedule.interview_time }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1 grow">
|
||||
<label class="text-[0.7rem] text-slate-500 font-semibold uppercase tracking-wider">{% trans "Interviewers" %}</label>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
{% for interviewer in interview_schedule.employee_id.all %}
|
||||
<span class="bg-indigo-100 text-indigo-900 px-2 py-0.5 rounded-xl text-sm font-medium">{{interviewer.get_full_name}}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% if interview_schedule.completed %}
|
||||
<div class="px-4 py-2 rounded-full text-sm font-semibold whitespace-nowrap bg-green-50 text-green-600 border border-green-200">
|
||||
{% trans "Interview Completed" %}
|
||||
</div>
|
||||
|
||||
{% elif interview_schedule.interview_date|date:"Y-m-d" == today %}
|
||||
<div class="px-4 py-2 rounded-full text-sm font-semibold whitespace-nowrap bg-blue-50 text-blue-600 border border-blue-200">
|
||||
{% trans "Interview Today" %}
|
||||
</div>
|
||||
|
||||
{% elif interview_schedule.interview_date|date:"Y-m-d" < today %}
|
||||
<div class="px-4 py-2 rounded-full text-sm font-semibold whitespace-nowrap bg-red-50 text-red-600 border border-red-200">
|
||||
{% trans "Expired Interview" %}
|
||||
</div>
|
||||
|
||||
{% elif interview_schedule.interview_date|date:"Y-m-d" > today %}
|
||||
<div class="px-4 py-2 rounded-full text-sm font-semibold whitespace-nowrap bg-orange-50 text-orange-600 border border-orange-200">
|
||||
{% trans "Upcoming Interview" %}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<div class="flex gap-1">
|
||||
<button class="w-8 h-8 rounded-md flex items-center justify-center transition-all bg-blue-50 text-blue-600 hover:bg-blue-100"
|
||||
title="{% trans 'Edit' %}"
|
||||
hx-get="{% url 'edit-interview' interview_schedule.id %}?view=false"
|
||||
data-target="#genericModal"
|
||||
hx-swap="innerHTML"
|
||||
hx-target="#genericModalBody"
|
||||
data-toggle="oh-modal-toggle"
|
||||
>
|
||||
<ion-icon
|
||||
name="create-outline"
|
||||
role="img"
|
||||
class="md"
|
||||
aria-label="create outline"
|
||||
></ion-icon>
|
||||
</button>
|
||||
|
||||
<button class="w-8 h-8 rounded-md flex items-center justify-center transition-all bg-red-50 text-red-600 hover:bg-red-100"
|
||||
title="{% trans 'Delete' %}"
|
||||
hx-get="{% url 'delete-interview' interview_schedule.id %}?view=false"
|
||||
data-target="#activitySidebar"
|
||||
hx-swap="innerHTML"
|
||||
hx-target="#interview"
|
||||
|
||||
>
|
||||
<ion-icon
|
||||
name="close-outline"
|
||||
role="img"
|
||||
class="md"
|
||||
aria-label="close outline"
|
||||
></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-slate-100 text-sm text-slate-900 pl-[85px] pb-5 pt-2">
|
||||
<label class="text-basesm font-medium text-slate-500 uppercase tracking-wider">{% trans "Description" %}</label> <br/>
|
||||
{{interview_schedule.description}}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% else %}
|
||||
<div class="flex items-center justify-between mt-4">
|
||||
<span class="font-semibold text-sm">
|
||||
{{ candidate }}'s {% trans "Scheduled Interviews" %}
|
||||
</span>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
hx-get="{% url 'interview-schedule' candidate.id %}"
|
||||
title="{% trans 'Schedule Interview' %}"
|
||||
hx-target="#genericModalBody"
|
||||
hx-swap="innerHTML"
|
||||
data-target="#genericModal"
|
||||
class="oh-btn oh-btn--secondary flex items-center gap-1 text-sm"
|
||||
data-toggle="oh-modal-toggle"
|
||||
>
|
||||
<ion-icon
|
||||
name="add"
|
||||
class="text-base"
|
||||
role="img"
|
||||
aria-label="add"
|
||||
></ion-icon>
|
||||
{% trans "Add" %}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="oh-wrapper h-full" align="center">
|
||||
<div
|
||||
class="xl:col-span-4 md:col-span-6 col-span-12 bg-white p-6 rounded-md shadow-card h-[70%]"
|
||||
>
|
||||
<div class="flex flex-col items-center justify-center h-full">
|
||||
<img
|
||||
src="/static/horilla_theme/assets/img/no-records.svg"
|
||||
alt=""
|
||||
width="300"
|
||||
class="mb-4"
|
||||
/>
|
||||
<p class="text-[#666] mb-5">
|
||||
{% trans "No interviews are scheduled for this candidate." %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<div id="gridView" class="p-5">
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
{% for instance in queryset %}
|
||||
<div class="border border-[#ebebeb] p-4 rounded-md shadow-card {{card_status_class|format:instance|safe}}" {{card_attrs|format:instance|safe}}>
|
||||
<div class="border border-[#ebebeb] p-4 rounded-md shadow-card cursor-pointer {{card_status_class|format:instance|safe}}" {{card_attrs|format:instance|safe}}>
|
||||
<div class="flex gap-5 relative">
|
||||
<div
|
||||
class="absolute inline-block right-0 -top-1" onclick="event.stopPropagation();"
|
||||
|
||||
@@ -216,6 +216,7 @@
|
||||
class="oh-btn oh-btn--secondary oh-btn--shadow pr-3 pl-3"
|
||||
onclick="event.stopPropagation();event.preventDefault;$('#filterChoose{{section_id}}').removeClass('oh-modal--show');"
|
||||
>
|
||||
<img src="/static/horilla_theme/assets/img/icons/more.svg" alt="Create" width="13" class="filter brightness-0 invert">
|
||||
{% trans "Add" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
{% load i18n %}
|
||||
<style>
|
||||
.oh-checkpoint-badge--success {
|
||||
color: yellowgreen;
|
||||
}
|
||||
.oh-checkpoint-badge {
|
||||
cursor: pointer;
|
||||
}
|
||||
.m-zero {
|
||||
margin: 0 !important;
|
||||
}
|
||||
</style>
|
||||
<div class="oh-filter-tag-container mb-2 p-0" id="filterTagContainer{{self.attrs.id}}">
|
||||
|
||||
</div>
|
||||
<div class="ration-container mb-2 d-flex justify-content-between align-items-center gap-2 flex-wrap">
|
||||
<div
|
||||
class="px-4 py-2 bg-[#73aae3] text-white rounded-md text-xs transition duration-300"
|
||||
data-toggle="oh-modal-toggle"
|
||||
data-target="#viewSelectedModal"
|
||||
>
|
||||
{% trans "Selected" %} <span class="selected-count">0</span>/<span class="total-count">{{queryset|length}}</span>
|
||||
</div>
|
||||
|
||||
<div class="px-4 py-2 bg-primary-600 text-white rounded-md text-xs hover:bg-primary-800 transition duration-300" style="cursor: pointer;margin-left: 7%;" id="selectAllUsers">
|
||||
{% trans "Select All" %} <span class="total-count visible-count">{{queryset|length}}</span> {% trans "user" %}
|
||||
</div>
|
||||
|
||||
<div class="px-4 py-2 bg-[#720c80] text-white rounded-md text-xs hover:bg-primary-800 transition duration-300" style="cursor: pointer;" id="unselectAllUsers">
|
||||
{% trans "Unselect All" %}
|
||||
</div>
|
||||
|
||||
<div class="px-4 py-2 bg-[#a4933b] text-white rounded-md text-xs hover:bg-primary-800 transition duration-300" style="cursor: pointer;" id="selectAllInstances">
|
||||
{% trans "Select All" %} {{queryset|length}} {% trans "Item" %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,152 @@
|
||||
{% load static i18n %}
|
||||
<div class="flex flex-wrap justify-between items-center mb-3 mt-5" id="widgetFilterFormContainer{{self.attrs.id}}">
|
||||
<!-- Left Side -->
|
||||
<h3 class="text-lg font-semibold">{{field.label}}</h3>
|
||||
|
||||
<!-- Right Side -->
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
|
||||
<!-- Search -->
|
||||
<div class="relative">
|
||||
<input type="text"
|
||||
class="text-color-600 ps-8 p-1.5 pb-2 placeholder:text-xs w-full border border-dark-50 rounded-md focus-visible:outline-0 placeholder:text-dark-100 text-sm transition duration-300 focus:border-primary-600"
|
||||
name="search"
|
||||
aria-label="Search Input"
|
||||
placeholder="{% trans 'Search' %}"
|
||||
autocomplete="off" />
|
||||
|
||||
<i class="fas fa-search absolute left-3 top-[10px] bottom-0 m-auto opacity-50 text-xs"></i>
|
||||
</div>
|
||||
|
||||
<!-- Filter Dropdown -->
|
||||
|
||||
<div class="oh-dropdown" x-data="{open: false}">
|
||||
<button
|
||||
hx-get="{% url 'get-filter-form' %}?template_path={{filter_template_path}}"
|
||||
hx-target="#widgetFilterContainer"
|
||||
hx-swap="innerHTML"
|
||||
hx-trigger="load"
|
||||
id="hxButton"
|
||||
hidden
|
||||
>
|
||||
<button
|
||||
onclick="$(this).closest('.oh-main__titlebar-button-container').find('#hxButton').click();"
|
||||
class="px-4 py-2 bg-white rounded-md text-xs flex items-center gap-2 border border-primary-500 hover:border-primary-600 transition duration-300 cursor-pointer"
|
||||
@click="open = !open">
|
||||
<img src="{% static 'horilla_theme/assets/img/icons/sort.svg' %}" alt="{% trans 'Filter' %}" width="15"
|
||||
class="mt-[-1px]"> {% trans "Filter" %}
|
||||
<div id="filterCount"></div>
|
||||
</button>
|
||||
</button>
|
||||
<div
|
||||
class="oh-dropdown__menu oh-dropdown__menu--left oh-dropdown__filter p-4"
|
||||
x-show="open"
|
||||
@click.outside="open = false"
|
||||
style="width: 395px;"
|
||||
>
|
||||
<div id="widgetFilterContainer">
|
||||
</div>
|
||||
<div class="oh-dropdown__filter-footer">
|
||||
<button
|
||||
type="submit"
|
||||
class="oh-btn oh-btn--secondary oh-btn--small w-100"
|
||||
data-action="{% url filter_route_name %}"
|
||||
id="widgetFilterButton{{self.attrs.id}}"
|
||||
>
|
||||
{% trans "Filter" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
function transformJson(inputJson) {
|
||||
// Clone the input JSON to avoid modifying the original object
|
||||
const modifiedJson = JSON.parse(JSON.stringify(inputJson));
|
||||
|
||||
// Iterate through each object in the JSON array
|
||||
modifiedJson.forEach((obj) => {
|
||||
// Remove "_id" when it appears at the end of a name
|
||||
|
||||
// If there are "__" in the name, keep only the word after the last "__" and capitalize it
|
||||
obj.name = obj.name.replace(/_id$/, "");
|
||||
obj.name.replace("_", " ");
|
||||
if (obj.name.includes("__")) {
|
||||
const parts = obj.name.split("__");
|
||||
obj.name = parts[parts.length - 1];
|
||||
}
|
||||
obj.name = obj.name.charAt(0).toUpperCase() + obj.name.slice(1);
|
||||
obj.name = obj.name.replace(/_/g, " ");
|
||||
});
|
||||
|
||||
return modifiedJson;
|
||||
}
|
||||
|
||||
$("#{{section_id}} #widgetFilterButton{{self.attrs.id}}").click(function (e) {
|
||||
e.preventDefault();
|
||||
const formFields = $("#{{section_id}} #widgetFilterFormContainer{{self.attrs.id}}").find(
|
||||
"[name]"
|
||||
);
|
||||
var formData = [];
|
||||
formFields.each(function () {
|
||||
const name = $(this).attr("name");
|
||||
const value = $(this).val();
|
||||
formData.push({ name, value });
|
||||
});
|
||||
var filterUrl = $(this).attr("data-action");
|
||||
$.ajax({
|
||||
type: "get",
|
||||
url: filterUrl,
|
||||
data: formData,
|
||||
success: function (response) {
|
||||
let ids = response.ids;
|
||||
$("#{{section_id}} #chooseTableHeaderParent .oh-sticky-table__tbody").hide();
|
||||
$.each(ids, function (indexInArray, valueOfElement) {
|
||||
$(
|
||||
`#{{section_id}} #chooseTableHeaderParent .oh-sticky-table__tbody[data-instance-id=${valueOfElement}]`
|
||||
).show();
|
||||
});
|
||||
$("#{{section_id}} .visible-count").html(
|
||||
$("#{{section_id}} .oh-sticky-table__tr--custom:visible .oh-sticky-table__sd")
|
||||
.length
|
||||
);
|
||||
var labeledTags = transformJson(formData);
|
||||
var tagContainer = $("#{{section_id}} #filterTagContainer{{self.attrs.id}}");
|
||||
tagContainer.html("");
|
||||
$.each(labeledTags, function (indexInArray, valueOfElement) {
|
||||
if (valueOfElement.value.length != 0) {
|
||||
tagContainer.append(
|
||||
$(`
|
||||
<span class="oh-filter-tag" id="tag-{{self.attrs.id}}"
|
||||
>${valueOfElement.name}<button class="oh-filter-tag__close" onclick="closeFilterTag(event, ${formData[indexInArray].name}, '#{{section_id}} #tag-{{self.attrs.id}}')">
|
||||
<ion-icon name="close-outline"></ion-icon></button
|
||||
>
|
||||
</span>`)
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
$("#{{section_id}} #widgetFilterFormContainer{{self.attrs.id}} [name=search]").keyup(
|
||||
function (e) {
|
||||
$("#{{section_id}} #widgetFilterButton{{self.attrs.id}}").click();
|
||||
}
|
||||
);
|
||||
});
|
||||
function closeFilterTag(e, fieldName, targetTag) {
|
||||
e.preventDefault();
|
||||
$(fieldName).val("");
|
||||
if ($(fieldName).is("select")) {
|
||||
$(fieldName)
|
||||
.next()
|
||||
.find(`#select2-${$(fieldName).attr("id")}-container`)
|
||||
.html("---------");
|
||||
}
|
||||
$("#{{section_id}} #widgetFilterButton{{self.attrs.id}}").click();
|
||||
$(targetTag).remove();
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,254 @@
|
||||
{% load i18n %}
|
||||
|
||||
<style>
|
||||
.oh-sticky-table {
|
||||
border: 1px solid #cdd5df;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 50vh; /* already in your inline style */
|
||||
}
|
||||
|
||||
.oh-sticky-table__thead {
|
||||
flex: 0 0 auto;
|
||||
background: #f8fafc;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
border-bottom: 1px solid #cdd5df;
|
||||
}
|
||||
|
||||
.oh-sticky-table__table {
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.oh-sticky-table__tr--custom {
|
||||
padding: 0.5rem;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.oh-sticky-table__tr--custom:hover {
|
||||
background: #f1f5f9;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<div class="oh-sticky-table mb-2" style="height: 50vh">
|
||||
<div
|
||||
class="oh-sticky-table__table oh-table--sortable"
|
||||
id="chooseTableHeaderParent"
|
||||
>
|
||||
<div class="oh-sticky-table__thead p-2" id="chooseTableHeader">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th oh-sticky-table__th--custom">
|
||||
<div class="d-flex">
|
||||
<div class="" >
|
||||
<input
|
||||
type="checkbox"
|
||||
title="Select all users"
|
||||
class="oh-input oh-input__checkbox mt-2 mr-2"
|
||||
id="choose-all-user"
|
||||
/>
|
||||
</div>
|
||||
<span style="margin-left:5%;" class="text-sm mt-1">{% trans "Employee" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% for instance in queryset %}
|
||||
<div class="oh-sticky-table__tbody" data-instance-id="{{instance.id}}">
|
||||
<div
|
||||
class="oh-sticky-table__tr oh-sticky-table__tr--custom"
|
||||
data-instance-id="{{instance.id}}"
|
||||
data-label="{{instance}}"
|
||||
data-avatar="{{instance.get_avatar}}"
|
||||
draggable="true"
|
||||
>
|
||||
<div
|
||||
class="oh-sticky-table__sd"
|
||||
id="selectRow{{self.attrs.id}}{{instance.id}}"
|
||||
>
|
||||
<div class="d-flex" style="margin-left:2%;">
|
||||
<div class="">
|
||||
<input
|
||||
type="checkbox"
|
||||
value="{{instance.id}}"
|
||||
class="oh-input oh-input__checkbox mt-2 mr-2 all-choose-user-row"
|
||||
/>
|
||||
</div>
|
||||
<div class="oh-profile oh-profile--md" style="margin-left:5%;">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img
|
||||
src="{{instance.get_avatar}}"
|
||||
class="oh-profile__image"
|
||||
/>
|
||||
</div>
|
||||
<span class="oh-profile__name text-[#666] text-sm">{{instance}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var selectedIds = [];
|
||||
$(document).ready(function () {
|
||||
$("#{{section_id}} #{{self.attrs.id}}").select2({
|
||||
multiple: true,
|
||||
});
|
||||
$("#{{section_id}} #{{self.attrs.id}}")
|
||||
.next()
|
||||
.find(".select2-container")
|
||||
.css("width", "100%");
|
||||
|
||||
$("#{{section_id}} #chooseTableHeader")
|
||||
.not("[type=checkbox]")
|
||||
.click(function (e) {
|
||||
e.preventDefault();
|
||||
if ($(this).find("[type=checkbox]:first").is(":checked")) {
|
||||
$(this).find("[type=checkbox]:first").prop("checked", false);
|
||||
} else {
|
||||
$(this).find("[type=checkbox]:first").prop("checked", true);
|
||||
}
|
||||
$("#{{section_id}} #choose-all-user").change();
|
||||
});
|
||||
$("#{{section_id}} #selectAllUsers").click(function (e) {
|
||||
e.preventDefault();
|
||||
$("#{{section_id}} #choose-all-user").prop("checked", true);
|
||||
$("#{{section_id}} #choose-all-user").change();
|
||||
});
|
||||
$("#{{section_id}} #unselectAllUsers").click(function (e) {
|
||||
e.preventDefault();
|
||||
$("#{{section_id}} #choose-all-user").prop("checked", false);
|
||||
$("#{{section_id}} #choose-all-user").change();
|
||||
});
|
||||
$("#{{section_id}} #choose-all-user").change(function (e) {
|
||||
e.preventDefault();
|
||||
if ($(this).is(":checked")) {
|
||||
$("#{{section_id}} .all-choose-user-row:visible").prop("checked", true);
|
||||
$("#{{section_id}} .oh-sticky-table__tr--custom:visible .oh-sticky-table__sd").addClass(
|
||||
"oh-sticky-table__tr--selected"
|
||||
);
|
||||
} else {
|
||||
$("#{{section_id}} .all-choose-user-row:visible").prop("checked", false);
|
||||
$(
|
||||
"#{{section_id}} .oh-sticky-table__tr--custom:visible .oh-sticky-table__sd"
|
||||
).removeClass("oh-sticky-table__tr--selected");
|
||||
}
|
||||
});
|
||||
$("#{{section_id}} .oh-sticky-table__tr--custom").click(function (e) {
|
||||
var checkbox = $(this).find("[type=checkbox]");
|
||||
|
||||
// Toggle the checkbox's checked state
|
||||
checkbox.prop("checked", function (i, checked) {
|
||||
if (!checked) {
|
||||
$(this)
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.addClass("oh-sticky-table__tr--selected");
|
||||
} else {
|
||||
$(this)
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.removeClass("oh-sticky-table__tr--selected");
|
||||
}
|
||||
return !checked;
|
||||
});
|
||||
});
|
||||
$("#{{section_id}} #filterChoose{{section_id}}").click(function (e) {
|
||||
e.preventDefault();
|
||||
var selectedRows = $("#{{section_id}} #filterChoose{{section_id}} div").find(
|
||||
".oh-sticky-table__tr--selected"
|
||||
);
|
||||
var ids = [];
|
||||
var instanceData = [];
|
||||
$.each(selectedRows, function (indexInArray, valueOfElement) {
|
||||
var id = $(valueOfElement).parent().attr("data-instance-id");
|
||||
var label = $(valueOfElement).parent().attr("data-label");
|
||||
ids.push(id);
|
||||
instanceData.push({ id: id, label: label });
|
||||
});
|
||||
var selectedCount = selectedRows.length;
|
||||
$("#{{section_id}} .selected-count").html(selectedCount);
|
||||
|
||||
$("#{{section_id}} #{{self.attrs.id}}").val(ids);
|
||||
$("#{{section_id}} #{{self.attrs.id}}").change();
|
||||
$("#{{section_id}} #avatarsContainer").html("");
|
||||
$.each(instanceData, function (indexInArray, valueOfElement) {
|
||||
var imgUrl = $(
|
||||
`#{{section_id}} .oh-sticky-table__tr.oh-sticky-table__tr--custom[data-instance-id=${valueOfElement.id}]`
|
||||
).attr("data-avatar");
|
||||
$("#{{section_id}} #avatarsContainer").append(
|
||||
$(
|
||||
`<a href="#" class="avatars__item" title="${valueOfElement.label}"><img class="avatar" src="${imgUrl}" alt=""></a>`
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
$("#{{section_id}} #selectAllInstances").click(function (e) {
|
||||
e.preventDefault();
|
||||
$("#{{section_id}} #choose-all-user").prop("checked", true);
|
||||
$("#{{section_id}} .all-choose-user-row").prop("checked", true);
|
||||
$("#{{section_id}} .oh-sticky-table__tr--custom .oh-sticky-table__sd").addClass(
|
||||
"oh-sticky-table__tr--selected"
|
||||
);
|
||||
$("#{{section_id}} #choose-all-user").change();
|
||||
});
|
||||
$("#{{section_id}} #{{ self.attrs.id }}").change(function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Get all selected options
|
||||
$("#{{section_id}} #avatarsContainer").html("");
|
||||
$("#{{section_id}} .oh-sticky-table__tr--selected")
|
||||
.find("[type=checkbox]")
|
||||
.prop("checked", false);
|
||||
$("#{{section_id}} .oh-sticky-table__tr--selected").removeClass(
|
||||
"oh-sticky-table__tr--selected"
|
||||
);
|
||||
var selectedOptions = $(this).find(`:selected`);
|
||||
$("#{{section_id}} .selected-count").html(selectedOptions.length);
|
||||
|
||||
// Loop through the selected options
|
||||
selectedOptions.each(function (indexInArray, valueOfElement) {
|
||||
// Get the HTML content of each selected option
|
||||
var optionHtml = $(this).html();
|
||||
// Append the selected option's HTML to the avatarsContainer
|
||||
var imgUrl = $(
|
||||
`#{{section_id}} .oh-sticky-table__tr.oh-sticky-table__tr--custom[data-instance-id=${$(
|
||||
valueOfElement
|
||||
).val()}]`
|
||||
).attr("data-avatar");
|
||||
$("#{{section_id}} #avatarsContainer").append(
|
||||
$(
|
||||
`<a href="#" class="avatars__item" title="${optionHtml}"><img class="avatar" src="${imgUrl}" alt=""></a>`
|
||||
)
|
||||
);
|
||||
var optValue = $(valueOfElement).val();
|
||||
var rowId = "#{{section_id}} #selectRow{{self.attrs.id}}" + optValue;
|
||||
$(rowId).addClass("oh-sticky-table__tr--selected");
|
||||
$(rowId).find("[type=checkbox]").prop("checked", true);
|
||||
});
|
||||
});
|
||||
{% if initial %}
|
||||
$('#{{section_id}} #selectContainer{{self.attrs.id}}').find("[name={{field_name}}]").val({{initial|safe}}).change()
|
||||
{% endif %}
|
||||
});
|
||||
$("#{{section_id}} #choose-all-user").click(function (e) {
|
||||
setTimeout(() => {
|
||||
$("#{{section_id}} #choose-all-user").closest(".oh-sticky-table__th--custom")[0].click()
|
||||
}, 2);
|
||||
});
|
||||
$("#{{section_id}} .all-choose-user-row").click(function (e) {
|
||||
e.preventDefault();
|
||||
setTimeout(() => {
|
||||
$(this).closest(".oh-sticky-table__tr--custom")[0].click()
|
||||
}, 1);
|
||||
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user