Add search to dashboard customer and order lists

This commit is contained in:
Nathan Chapman 2023-07-04 15:06:45 -06:00
parent cb6f311d68
commit 156b90a213
5 changed files with 77 additions and 12 deletions

View File

@ -10,7 +10,12 @@
</header> </header>
<section class="panel"> <section class="panel">
<header class="panel-header"> <header class="panel-header">
<h4></h4> <form class="search-form">
<input type="search" placeholder="Search customers by name or email" name="q" {% if query %}value="{{query}}"{% endif %}>
{% if query %}
<a href="{% url 'dashboard:customer-list' %}"><button type="button">Clear search</button></a>
{% endif %}
</form>
</header> </header>
<table> <table>
<thead> <thead>

View File

@ -10,7 +10,12 @@
</header> </header>
<section class="panel"> <section class="panel">
<header class="panel-header"> <header class="panel-header">
<h3></h3> <form class="search-form">
<input type="search" placeholder="Search orders by no. or customer" name="q" {% if query %}value="{{query}}"{% endif %}>
{% if query %}
<a href="{% url 'dashboard:order-list' %}"><button type="button">Clear search</button></a>
{% endif %}
</form>
</header> </header>
<table> <table>
{% include 'dashboard/order/_table.html' with order_list=order_list %} {% include 'dashboard/order/_table.html' with order_list=order_list %}

View File

@ -226,19 +226,28 @@ class OrderListView(LoginRequiredMixin, ListView):
paginate_by = 50 paginate_by = 50
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get('status') status = self.request.GET.get('status')
if query == 'unfulfilled': query = self.request.GET.get('q')
object_list = Order.objects.filter(
Q(status=OrderStatus.UNFULFILLED) |
Q(status=OrderStatus.PARTIALLY_FULFILLED)
).order_by('-created_at').select_related('customer')
else: object_list = Order.objects.order_by(
object_list = Order.objects.order_by(
'-created_at' '-created_at'
).select_related('customer') ).select_related('customer')
return object_list if status == 'unfulfilled':
object_list = object_list.filter(
Q(status=OrderStatus.UNFULFILLED) |
Q(status=OrderStatus.PARTIALLY_FULFILLED)
)
if query:
object_list = find_order_by_no_or_customer(object_list, query)
return object_list.order_by('-created_at').select_related('customer')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["query"] = self.request.GET.get("q")
return context
class OrderDetailView(LoginRequiredMixin, DetailView): class OrderDetailView(LoginRequiredMixin, DetailView):
@ -641,12 +650,33 @@ def update_sorting(request):
return JsonResponse({'message': 'Sorting updated'}) return JsonResponse({'message': 'Sorting updated'})
def find_user_by_name_or_email(qs, query):
for term in query.split():
qs = qs.filter(
Q(first_name__icontains = term) | Q(last_name__icontains = term)
| Q(email__icontains = term)
)
return qs
def find_order_by_no_or_customer(qs, query):
for term in query.split():
qs = qs.filter(
Q(pk__icontains = term)
| Q(customer__first_name__icontains = term)
| Q(customer__last_name__icontains = term)
| Q(customer__email__icontains = term)
)
return qs
class CustomerListView(LoginRequiredMixin, ListView): class CustomerListView(LoginRequiredMixin, ListView):
model = User model = User
template_name = 'dashboard/customer/list.html' template_name = 'dashboard/customer/list.html'
paginate_by = 100 paginate_by = 100
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get('q')
object_list = User.objects.filter( object_list = User.objects.filter(
Exists( Exists(
Order.objects.filter(customer=OuterRef('pk')) Order.objects.filter(customer=OuterRef('pk'))
@ -657,9 +687,18 @@ class CustomerListView(LoginRequiredMixin, ListView):
num_orders=Count('orders') num_orders=Count('orders')
).order_by('first_name', 'last_name') ).order_by('first_name', 'last_name')
if query:
object_list = find_user_by_name_or_email(object_list, query)
return object_list return object_list
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["query"] = self.request.GET.get("q")
return context
class CustomerDetailView(LoginRequiredMixin, DetailView): class CustomerDetailView(LoginRequiredMixin, DetailView):
model = User model = User
template_name = 'dashboard/customer/detail.html' template_name = 'dashboard/customer/detail.html'

View File

@ -3,7 +3,7 @@
--color-bg: #eff5f8; --color-bg: #eff5f8;
--color-bg-alt: #bdc8d2; --color-bg-alt: #bdc8d2;
--color-rgb-bg-alt: 189, 200, 210; --color-rgb-bg-alt: 189, 200, 210;
--color-gray: #9d9d9d; --color-gray: #9d9d9d;
--color-yellow: #f8a911; --color-yellow: #f8a911;
--color-yellow-alt: #f6c463; --color-yellow-alt: #f6c463;
--color-yellow-highlight: #f9e476; --color-yellow-highlight: #f9e476;
@ -153,6 +153,7 @@ tfoot th {
input[type=text], input[type=text],
input[type=email], input[type=email],
input[type=number], input[type=number],
input[type=search],
input[type=date], input[type=date],
input[type=password], input[type=password],
select[multiple=multiple], select[multiple=multiple],
@ -205,6 +206,10 @@ input[type=radio] {
vertical-align: middle; vertical-align: middle;
} }
input[type=search] {
width: 100%;
}
.btn, .btn,
input[type=submit], input[type=submit],
button { button {
@ -409,6 +414,16 @@ main > article > header {
border-bottom: var(--default-border); border-bottom: var(--default-border);
} }
.search-form {
width: 100%;
display: flex;
gap: 1rem;
align-items: center;
}
a button {
white-space: nowrap;
}
@media screen and (max-width: 800px) { @media screen and (max-width: 800px) {
.object-header, .object-header,
.panel-header { .panel-header {

View File

@ -159,6 +159,7 @@ input[type=checkbox] {
width: 2rem; width: 2rem;
height: 2rem; height: 2rem;
vertical-align: middle; vertical-align: middle;
accent-color: var(--yellow-color);
} }
input[type=radio] + label, input[type=radio] + label,