Files
penracourses/generic/templates/generic/trainees.html
T

210 lines
8.4 KiB
HTML

{% extends 'generic/base.html' %}
{% load crispy_forms_tags %}
{% block css %}
{% endblock %}
{% block content %}
<a href='{% url "trainees" %}'>All, </a>
{% for i in "123456"|make_list %}
<a href='{% url "trainees_grade" "ST"|add:i %}'>ST{{i}}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
(<a href="{% url 'create_trainee' %}" title="Click to add a trainee to the platform, creating an account for them.">Add trainee</a>)
(<a href="{% url 'accounts_bulk_create' %}" title="Click to create multiple trainees at once.">Bulk create</a>)
(<a href="{% url 'trainees_bulk_update_from_spreadsheet' %}" title="Click to update multiple trainees at once.">Bulk update</a>)
<h2>
{% if grade %}
{{grade}}
{% endif %}Trainees
</h2>
<form>
<table id="trainees-table">
<tr class="header">
<th class="sortable" data-col="0">Name <span class="sort-indicator"></span></th>
<th class="sortable" data-col="1">Grade <span class="sort-indicator"></span></th>
<th class="sortable" data-col="2">Email <span class="sort-indicator"></span></th>
<th class="sortable" data-col="3">Supervisor <span class="sort-indicator"></span></th>
<th>Edit</th>
<th class="trainee-bulk-edit">Bulk Edit<br/>
<span _="on click log 'test' then log 'hello' then repeat for i in <input/>
-- set i.checked to not i.checked
toggle [@checked] on i
">Toggle All</span>
</th>
</tr>
{% for trainee in trainees %}
<tr class="trainee" _="on click log 'test' then log the next <input/> then toggle [@checked] on <input/> in me">
<td>{{trainee.user.first_name}} {{trainee.user.last_name}}
<a href="{% url 'account_profile' trainee.username %}" class="opacity-25"><i class="bi bi-link"></i></a>
</td>
<td
{% if not trainee.grade %}
class="no-grade"
{% endif %}
>{{trainee.grade}}{% if not trainee.grade %}
<a href="{% url 'account_profile_update' trainee.user.username %}?redirect={{request.path}}" class="add-grade">add</a>
{% endif %}
</td>
<td>{{trainee.user.email}}</td>
<td
{% if not trainee.supervisor %}
class="no-supervisor"
{% endif %}
>{{trainee.supervisor}}
{% if not trainee.supervisor %}
<a href="{% url 'account_profile_update' trainee.user.username %}?redirect={{request.path}}" class="add-supervisor">add</a>
{% else %}
<a href="{% url 'generic:supervisor_detail' trainee.supervisor.pk %}" class="opacity-25"><i class="bi bi-link"></i></a>
{% endif %}
</td>
<td><a href="{% url 'account_update' trainee.user.username %}?redirect={{request.path}}">User</a>/<a href="{% url 'account_profile_update' trainee.user.username %}?redirect={{request.path}}">Profile</a>
<span class="hover-highlight remove-trainee"><i class="bi bi-x-circle" title="Click to remove trainee status"
hx-get = "{% url 'generic:user_not_trainee' trainee.user.pk %}"
></i></span>
</td>
<td class="trainee-bulk-edit">
<input class="trainee-checkbox" type="checkbox" name="selection" value="{{trainee.user.pk}}">
</td>
</tr>
{% endfor %}
</table>
</form>
<div class="small-gray">Count: {{trainees|length}}</div>
<button class="btn btn-sm"
_="on click toggle .show on .remove-trainee"
>Remove trainee status</button>
<button class="btn btn-sm"
_="on click toggle .show on .trainee-bulk-edit"
>Bulk edit trainees</button>
<div id="bulk-edit" class="trainee-bulk-edit">
<h3>Bulk edit options</h3>
These actions will act on all the selected trainees. Refresh the page to cancel / clear.
<div id="htmx-info"></div>
<div id="htmx-options"></div>
<button id="bulk-delete-supervisors-button"
title="Deletes the supervisors of all selected users"
hx-post="{% url 'generic:users_bulk_delete_supervisors' %}"
hx-include="[name='selection']"
hx-confirm="This will delete supervisors from all selected users, are you sure you wish to continue?"
hx-target="#htmx-info"
_='on click put "" into #htmx-options'
>Delete supervisors</button>
<button id="bulk-edit-grade-button"
hx-post="{% url 'generic:users_bulk_edit' %}"
hx-include="[name='selection']"
hx-target="#htmx-options"
title="Changes the selected users grade."
>Edit grade</button>
<button id="bulk-deactivate-user-button"
hx-post="{% url 'generic:users_bulk_edit' %}"
hx-include="[name='selection']"
hx-target="#htmx-options"
hx-confirm="This will deactivate all selected users, are you sure you wish to continue?"
title="Deactivates the selected users"
>Deactivate</button>
</div>
<style>
.add-supervisor, .add-grade {
font-size: small;
}
.no-supervisor, .no-grade {
color: red;
opacity: 50%;
}
.remove-trainee, .trainee-bulk-edit {
display: none;
}
#bulk-edit {
display: none;
}
.show {
display: inline !important;
}
td {
padding-right: 8px;
}
tr:hover {
box-shadow: 0 0 2px #ccc;
}
tr:has(.trainee-checkbox:checked) {
background-color: darkgrey;
color: white;
}
th.sortable {
cursor: pointer;
user-select: none;
}
th .sort-indicator {
font-size: 0.8em;
margin-left: 6px;
opacity: 0.6;
}
</style>
<script>
(function(){
const table = document.getElementById('trainees-table');
if (!table) return;
const getCellValue = (tr, idx) => {
const cell = tr.children[idx];
return cell ? cell.innerText.trim().toLowerCase() : '';
};
const comparer = function(idx, asc){
return function(a,b){
const v1 = getCellValue(a, idx);
const v2 = getCellValue(b, idx);
// attempt numeric compare
const n1 = parseFloat(v1.replace(/[^0-9.\-]/g, ''));
const n2 = parseFloat(v2.replace(/[^0-9.\-]/g, ''));
if (!isNaN(n1) && !isNaN(n2)){
return (n1 - n2) * (asc ? 1 : -1);
}
return v1.localeCompare(v2) * (asc ? 1 : -1);
};
};
let lastSorted = {idx: null, asc: true};
table.querySelectorAll('th.sortable').forEach(th => {
th.addEventListener('click', function(){
const idx = parseInt(th.getAttribute('data-col'));
const tbodyRows = Array.from(table.querySelectorAll('tr.trainee'));
const asc = (lastSorted.idx === idx) ? !lastSorted.asc : true;
tbodyRows.sort(comparer(idx, asc));
// re-append rows in new order
const parent = table;
tbodyRows.forEach(r => parent.appendChild(r));
// update indicators
table.querySelectorAll('th.sortable .sort-indicator').forEach(el => el.textContent = '');
th.querySelector('.sort-indicator').textContent = asc ? '▲' : '▼';
lastSorted = {idx, asc};
});
});
})();
</script>
{% endblock %}