mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-10 11:59:23 +00:00
Make product types dynamically orderable.
This commit is contained in:
64
counter/static/bundled/counter/product-type-index.ts
Normal file
64
counter/static/bundled/counter/product-type-index.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import Alpine from "alpinejs";
|
||||
import { producttypeReorder } from "#openapi";
|
||||
|
||||
document.addEventListener("alpine:init", () => {
|
||||
Alpine.data("productTypesList", () => ({
|
||||
loading: false,
|
||||
alertMessage: {
|
||||
open: false,
|
||||
success: true,
|
||||
content: "",
|
||||
timeout: null,
|
||||
},
|
||||
|
||||
async reorder(itemId: number, newPosition: number) {
|
||||
// The sort plugin of Alpine doesn't manage dynamic lists with x-sort
|
||||
// (cf. https://github.com/alpinejs/alpine/discussions/4157).
|
||||
// There is an open PR that fixes this issue
|
||||
// (cf. https://github.com/alpinejs/alpine/pull/4361).
|
||||
// However, it hasn't been merged yet.
|
||||
// To overcome this, I get the list of DOM elements
|
||||
// And fetch the `x-sort:item` attribute, which value is
|
||||
// the id of the object in database.
|
||||
// Please make this a little bit cleaner when the fix has been merged
|
||||
// into the main Alpine repo.
|
||||
this.loading = true;
|
||||
const productTypes = this.$refs.productTypes
|
||||
.childNodes as NodeListOf<HTMLLIElement>;
|
||||
const getId = (elem: HTMLLIElement) =>
|
||||
Number.parseInt(elem.getAttribute("x-sort:item"));
|
||||
const query =
|
||||
newPosition === 0
|
||||
? { above: getId(productTypes.item(1)) }
|
||||
: { below: getId(productTypes.item(newPosition - 1)) };
|
||||
const response = await producttypeReorder({
|
||||
// biome-ignore lint/style/useNamingConvention: api is snake_case
|
||||
path: { type_id: itemId },
|
||||
query: query,
|
||||
});
|
||||
this.openAlertMessage(response.response);
|
||||
this.loading = false;
|
||||
},
|
||||
|
||||
openAlertMessage(response: Response) {
|
||||
if (response.ok) {
|
||||
this.alertMessage.success = true;
|
||||
this.alertMessage.content = gettext("Products types successfully reordered");
|
||||
} else {
|
||||
this.alertMessage.success = false;
|
||||
this.alertMessage.content = interpolate(
|
||||
gettext("Product type reorganisation failed with status code : %d"),
|
||||
[response.status],
|
||||
);
|
||||
}
|
||||
this.alertMessage.open = true;
|
||||
if (this.alertMessage.timeout !== null) {
|
||||
clearTimeout(this.alertMessage.timeout);
|
||||
}
|
||||
this.alertMessage.timeout = setTimeout(() => {
|
||||
this.alertMessage.open = false;
|
||||
}, 2000);
|
||||
this.loading = false;
|
||||
},
|
||||
}));
|
||||
});
|
15
counter/static/counter/css/product_type.scss
Normal file
15
counter/static/counter/css/product_type.scss
Normal file
@ -0,0 +1,15 @@
|
||||
.product-type-list {
|
||||
li {
|
||||
list-style: none;
|
||||
margin-bottom: 10px;
|
||||
|
||||
i {
|
||||
cursor: grab;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body:not(.sorting) .product-type-list li:hover i {
|
||||
visibility: visible;
|
||||
}
|
@ -4,21 +4,49 @@
|
||||
{% trans %}Product type list{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block additional_css %}
|
||||
<link rel="stylesheet" href="{{ static("counter/css/product_type.scss") }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block additional_js %}
|
||||
<script type="module" src="{{ static("bundled/counter/product-type-index.ts") }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p><a href="{{ url('counter:new_producttype') }}">{% trans %}New product type{% endtrans %}</a></p>
|
||||
{% if producttype_list %}
|
||||
<h3>{% trans %}Product type list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for t in producttype_list %}
|
||||
<li><a href="{{ url('counter:producttype_edit', type_id=t.id) }}">{{ t }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<div x-data="productTypesList">
|
||||
<p
|
||||
class="alert snackbar"
|
||||
:class="alertMessage.success ? 'alert-green' : 'alert-red'"
|
||||
x-show="alertMessage.open"
|
||||
x-transition.duration.500ms
|
||||
x-text="alertMessage.content"
|
||||
></p>
|
||||
<h3>{% trans %}Product type list{% endtrans %}</h3>
|
||||
<ul
|
||||
x-sort="($item, $position) => reorder($item, $position)"
|
||||
x-ref="productTypes"
|
||||
class="product-type-list"
|
||||
:aria-busy="loading"
|
||||
>
|
||||
{%- for t in producttype_list -%}
|
||||
<li x-sort:item="{{ t.id }}">
|
||||
<i class="fa fa-grip-vertical"></i>
|
||||
<a href="{{ url('counter:producttype_edit', type_id=t.id) }}">{{ t }}</a>
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
{% trans %}There is no product types in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block script %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user