improved search and UI on teams page
This commit is contained in:
parent
0f1c839daa
commit
439ae32a79
@ -5,24 +5,35 @@
|
|||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="bg-body-secondary p-4">
|
<div class="bg-body p-4">
|
||||||
<a href="{% url 'index' %}" class="btn btn-primary px-4">Back</a>
|
<a href="{% url 'index' %}" class="btn btn-primary px-4">Back</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container my-4 p-4 bg-body-secondary rounded">
|
<div class="container my-4 p-4 pb-0 bg-body-secondary rounded">
|
||||||
<div class="row">
|
<div class="row mb-4">
|
||||||
<div class="col-md-6 col-xl-8">
|
<div class="col-md-6 col-xl-8">
|
||||||
<h3 class="mb-4">Teams & their Members</h3>
|
<h3 class="mb-0">Teams & Members</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-xl-4">
|
<div class="col-md-6 col-xl-4">
|
||||||
<div class="input-group mb-4 mb-md-0">
|
<div class="input-group mb-4 mb-md-0">
|
||||||
<input type="search" class="form-control" placeholder="Search" id="search">
|
<input type="search" class="form-control" placeholder="Search Members" id="search">
|
||||||
<button type="button" class="btn border"><i class="bi bi-search"></i></button>
|
<button type="button" class="btn border bg-body"><i class="bi bi-search"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" id="teamsContainer"></div>
|
<div class="row" id="teamsContainer"></div>
|
||||||
|
<div class="col-12 text-center pb-4" id="teamsLoadingSpinner">
|
||||||
|
<div class="spinner-border spinner-border-lg" role="status">
|
||||||
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pb-4" id="teamsNotFound">
|
||||||
|
<div class="alert alert-danger m-0" role="alert">
|
||||||
|
No teams found under that search
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Edit Modal -->
|
<!-- Edit Modal -->
|
||||||
@ -60,21 +71,67 @@
|
|||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
jQuery.expr[':'].icontains = function(a, i, m) {
|
||||||
|
return jQuery(a).text().toUpperCase()
|
||||||
|
.indexOf(m[3].toUpperCase()) >= 0;
|
||||||
|
};
|
||||||
|
|
||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
loadTeams();
|
teamsLoading(true);
|
||||||
|
fetchAndLoadTeams();
|
||||||
|
|
||||||
var searchTimeout = null;
|
var searchTimeout = null;
|
||||||
|
|
||||||
$("#search").keyup(() => {
|
$("#search").keyup(() => {
|
||||||
clearTimeout(searchTimeout);
|
clearTimeout(searchTimeout);
|
||||||
|
teamsLoading(true);
|
||||||
|
|
||||||
searchTimeout = setTimeout(() => {
|
searchTimeout = setTimeout(() => {
|
||||||
loadTeams($("#search").val());
|
fetchAndLoadTeams($("#search").val());
|
||||||
}, 500)
|
}, 500)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function loadTeams(search="") {
|
function loadTeams(teams, highlightText="") {
|
||||||
|
$("#teamsContainer").html(""); // Clear the previous listed teams
|
||||||
|
|
||||||
|
if (teams.length < 1) {
|
||||||
|
$("#teamsNotFound").show()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over and add each team
|
||||||
|
teams.forEach((team) => {
|
||||||
|
$("#teamsContainer").append(
|
||||||
|
`<div class='col-12 col-md-6 col-xl-4 mb-4'>
|
||||||
|
<div class='p-4 bg-body-tertiary rounded h-100 fluid-hover-zoom shadow-sm hover-shadow'>
|
||||||
|
<h4>${team.identifier}</h4>
|
||||||
|
<ul class='list-unstyled ul-cols-2 team-members'>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
);
|
||||||
|
|
||||||
|
// While we have the team, iterate over and add it's members
|
||||||
|
team.members.forEach((member) => {
|
||||||
|
$("#teamsContainer").find(".team-members").last().append(
|
||||||
|
`<li>
|
||||||
|
<span
|
||||||
|
type='button'
|
||||||
|
class='team-member'
|
||||||
|
onclick='javascript:openEditModal("${member.name}");'
|
||||||
|
>
|
||||||
|
${member.name}
|
||||||
|
</span>
|
||||||
|
</li>`
|
||||||
|
)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (highlightText) {
|
||||||
|
$("#teamsContainer").find(`.team-member:icontains('${highlightText}')`).css("color", "red")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchAndLoadTeams(search) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "{% url 'get-teams' %}",
|
url: "{% url 'get-teams' %}",
|
||||||
type: "post",
|
type: "post",
|
||||||
@ -82,36 +139,27 @@
|
|||||||
"csrfmiddlewaretoken": "{{ csrf_token }}",
|
"csrfmiddlewaretoken": "{{ csrf_token }}",
|
||||||
"search": search
|
"search": search
|
||||||
},
|
},
|
||||||
success: (results) => {
|
error: (xhr, textStatus, errorThrown) => { alert(errorThrown); },
|
||||||
$("#teamsContainer").html("");
|
success: (result) => {
|
||||||
|
teamsLoading(false)
|
||||||
for (var i = 0; i < results.teams.length; i++) {
|
loadTeams(result.teams, search);
|
||||||
var team = results.teams[i];
|
|
||||||
$("#teamsContainer").append(
|
|
||||||
"<div class='col-12 col-md-6 col-xl-4 mb-4'>" +
|
|
||||||
"<div class='p-4 bg-body-tertiary rounded h-100'>" +
|
|
||||||
`<h4>${team.identifier}</h4>` +
|
|
||||||
"<ul class='list-unstyled ul-cols-2 team-members'>" +
|
|
||||||
"</ul>" +
|
|
||||||
"</div>" +
|
|
||||||
"</div>"
|
|
||||||
);
|
|
||||||
for (var j = 0; j < team.members.length; j++) {
|
|
||||||
var member = team.members[j];
|
|
||||||
$("#teamsContainer").find(".team-members").last().append(
|
|
||||||
"<li>" +
|
|
||||||
`<span type='button' class='team-member' onclick='javascript:openEditModal("${member.name}");'>${member.name}</span>` +
|
|
||||||
"</li>"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: (xhr, textStatus, errorThrown) => {
|
|
||||||
alert(errorThrown);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function teamsLoading(show=true) {
|
||||||
|
$("#teamsNotFound").hide()
|
||||||
|
|
||||||
|
if (show) {
|
||||||
|
$("#teamsContainer").hide();
|
||||||
|
$("#teamsLoadingSpinner").show();
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#teamsContainer").show();
|
||||||
|
$("#teamsLoadingSpinner").hide();
|
||||||
|
}
|
||||||
|
|
||||||
function openEditModal(name) {
|
function openEditModal(name) {
|
||||||
|
|
||||||
var [first, last] = name.split(" ");
|
var [first, last] = name.split(" ");
|
||||||
|
@ -6,7 +6,6 @@ from django.shortcuts import render, redirect
|
|||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
|
|
||||||
from .models import Peg
|
from .models import Peg
|
||||||
from .teams_demo_test import created_teams
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
return render(request, 'index.html')
|
return render(request, 'index.html')
|
||||||
@ -38,12 +37,32 @@ def get_teams(request):
|
|||||||
|
|
||||||
search = request.POST.get("search")
|
search = request.POST.get("search")
|
||||||
|
|
||||||
if search:
|
from .teams_demo_test import created_teams
|
||||||
created_teams.sort(reverse=True, key=lambda team: next((
|
|
||||||
member["name"] for member in team["members"]
|
|
||||||
if search.lower() in member["name"].lower()), ""
|
|
||||||
))
|
|
||||||
else:
|
|
||||||
created_teams.sort(reverse=False, key=lambda team: team["identifier"])
|
|
||||||
|
|
||||||
|
if search:
|
||||||
|
unfiltered_teams = created_teams.copy()
|
||||||
|
created_teams = [
|
||||||
|
team for team in unfiltered_teams
|
||||||
|
if any(
|
||||||
|
search.lower() in name for name in
|
||||||
|
[member["name"].lower() for member in team["members"]]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
created_teams.sort(reverse=False, key=lambda team: team["identifier"])
|
||||||
return JsonResponse({"teams": created_teams})
|
return JsonResponse({"teams": created_teams})
|
||||||
|
|
||||||
|
# if not search:
|
||||||
|
# created_teams.sort(reverse=False, key=lambda team: team["identifier"])
|
||||||
|
# return JsonResponse({"teams": created_teams})
|
||||||
|
|
||||||
|
# # Create a new list only containing teams that meet the search criteria
|
||||||
|
# filtered_teams = []
|
||||||
|
# for team in created_teams:
|
||||||
|
# member_names = [member["name"].lower() for member in team["members"]]
|
||||||
|
# if any(search.lower() in name for name in member_names):
|
||||||
|
# filtered_teams.append(team)
|
||||||
|
|
||||||
|
# filtered_teams.sort(reverse=False, key=lambda team: team["identifier"])
|
||||||
|
|
||||||
|
# return JsonResponse({"teams": filtered_teams})
|
||||||
|
@ -10,3 +10,23 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spinner-border-lg {
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fluid-hover-zoom {
|
||||||
|
transition: .3s
|
||||||
|
transform cubic-bezier(.155,1.105,.295,1.12),
|
||||||
|
.3s box-shadow,
|
||||||
|
.3s -webkit-transform cubic-bezier(.155,1.105,.295,1.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fluid-hover-zoom:hover {
|
||||||
|
transform: scale(1.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-shadow:not(:hover) {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user