Merge pull request #1029 from ae-utbm/product-filter

add club and counter filters on product list page
This commit is contained in:
thomas girod 2025-02-26 16:20:03 +01:00 committed by GitHub
commit 6a17e4480e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 64 additions and 23 deletions

View File

@ -464,7 +464,7 @@ body {
flex-wrap: wrap; flex-wrap: wrap;
$col-gap: 1rem; $col-gap: 1rem;
$row-gap: 0.5rem; $row-gap: $col-gap / 3;
&.gap { &.gap {
column-gap: $col-gap; column-gap: $col-gap;

View File

@ -98,3 +98,5 @@ class ProductFilterSchema(FilterSchema):
is_archived: bool | None = Field(None, q="archived") is_archived: bool | None = Field(None, q="archived")
buying_groups: set[int] | None = Field(None, q="buying_groups__in") buying_groups: set[int] | None = Field(None, q="buying_groups__in")
product_type: set[int] | None = Field(None, q="product_type__in") product_type: set[int] | None = Field(None, q="product_type__in")
club: set[int] | None = Field(None, q="club__in")
counter: set[int] | None = Field(None, q="counters__in")

View File

@ -60,6 +60,8 @@ document.addEventListener("alpine:init", () => {
productStatus: "" as "active" | "archived" | "both", productStatus: "" as "active" | "archived" | "both",
search: "", search: "",
productTypes: [] as string[], productTypes: [] as string[],
clubs: [] as string[],
counters: [] as string[],
pageSize: defaultPageSize, pageSize: defaultPageSize,
page: defaultPage, page: defaultPage,
@ -67,13 +69,27 @@ document.addEventListener("alpine:init", () => {
const url = getCurrentUrlParams(); const url = getCurrentUrlParams();
this.search = url.get("search") || ""; this.search = url.get("search") || "";
this.productStatus = url.get("productStatus") ?? "active"; this.productStatus = url.get("productStatus") ?? "active";
const widget = this.$refs.productTypesInput.widget as TomSelect; const productTypesWidget = this.$refs.productTypesInput.widget as TomSelect;
widget.on("change", (items: string[]) => { productTypesWidget.on("change", (items: string[]) => {
this.productTypes = [...items]; this.productTypes = [...items];
}); });
const clubsWidget = this.$refs.clubsInput.widget as TomSelect;
clubsWidget.on("change", (items: string[]) => {
this.clubs = [...items];
});
const countersWidget = this.$refs.countersInput.widget as TomSelect;
countersWidget.on("change", (items: string[]) => {
this.counters = [...items];
});
await this.load(); await this.load();
const searchParams = ["search", "productStatus", "productTypes"]; const searchParams = [
"search",
"productStatus",
"productTypes",
"clubs",
"counters",
];
for (const param of searchParams) { for (const param of searchParams) {
this.$watch(param, () => { this.$watch(param, () => {
this.page = defaultPage; this.page = defaultPage;
@ -109,6 +125,8 @@ document.addEventListener("alpine:init", () => {
is_archived: isArchived, is_archived: isArchived,
// biome-ignore lint/style/useNamingConvention: api is in snake_case // biome-ignore lint/style/useNamingConvention: api is in snake_case
product_type: [...this.productTypes], product_type: [...this.productTypes],
club: [...this.clubs],
counter: [...this.counters],
}, },
}; };
}, },
@ -121,14 +139,17 @@ document.addEventListener("alpine:init", () => {
const options = this.getQueryParams(); const options = this.getQueryParams();
const resp = await productSearchProductsDetailed(options); const resp = await productSearchProductsDetailed(options);
this.nbPages = Math.ceil(resp.data.count / defaultPageSize); this.nbPages = Math.ceil(resp.data.count / defaultPageSize);
this.products = resp.data.results.reduce<GroupedProducts>((acc, curr) => { this.products = resp.data.results.reduce<GroupedProducts>(
(acc: GroupedProducts, curr: ProductSchema) => {
const key = curr.product_type?.name ?? gettext("Uncategorized"); const key = curr.product_type?.name ?? gettext("Uncategorized");
if (!(key in acc)) { if (!(key in acc)) {
acc[key] = []; acc[key] = [];
} }
acc[key].push(curr); acc[key].push(curr);
return acc; return acc;
}, {}); },
{},
);
this.loading = false; this.loading = false;
}, },

View File

@ -7,6 +7,7 @@
{% block additional_js %} {% block additional_js %}
<script type="module" src="{{ static("bundled/counter/components/ajax-select-index.ts") }}"></script> <script type="module" src="{{ static("bundled/counter/components/ajax-select-index.ts") }}"></script>
<script type="module" src="{{ static("bundled/club/components/ajax-select-index.ts") }}"></script>
<script type="module" src="{{ static("bundled/counter/product-list-index.ts") }}"></script> <script type="module" src="{{ static("bundled/counter/product-list-index.ts") }}"></script>
{% endblock %} {% endblock %}
@ -22,7 +23,6 @@
<h4 class="margin-bottom">{% trans %}Filter products{% endtrans %}</h4> <h4 class="margin-bottom">{% trans %}Filter products{% endtrans %}</h4>
<form id="search-form" class="margin-bottom"> <form id="search-form" class="margin-bottom">
<div class="row gap-4x"> <div class="row gap-4x">
<fieldset> <fieldset>
<label for="search-input">{% trans %}Product name{% endtrans %}</label> <label for="search-input">{% trans %}Product name{% endtrans %}</label>
<input <input
@ -48,16 +48,34 @@
</div> </div>
</fieldset> </fieldset>
</div> </div>
<fieldset> <div class="row gap-4x">
<fieldset class="grow">
<label for="type-search-input">{% trans %}Product type{% endtrans %}</label> <label for="type-search-input">{% trans %}Product type{% endtrans %}</label>
<product-type-ajax-select <product-type-ajax-select
id="type-search-input" id="type-search-input"
name="product-type" name="product-type"
x-ref="productTypesInput" x-ref="productTypesInput"
multiple multiple
> ></product-type-ajax-select>
</product-type-ajax-select>
</fieldset> </fieldset>
<fieldset class="grow">
<label for="club-search-input">{% trans %}Clubs{% endtrans %}</label>
<club-ajax-select
id="club-search-input"
name="club"
x-ref="clubsInput"
multiple></club-ajax-select>
</fieldset>
<fieldset class="grow">
<label for="counter-search-input">{% trans %}Counters{% endtrans %}</label>
<counter-ajax-select
id="counter-search-input"
name="counter"
x-ref="countersInput"
multiple
></counter-ajax-select>
</fieldset>
</div>
</form> </form>
<h3 class="margin-bottom">{% trans %}Product list{% endtrans %}</h3> <h3 class="margin-bottom">{% trans %}Product list{% endtrans %}</h3>