Add toast notification system
Django CI/CD / test (push) Successful in 35s
Django CI/CD / build-and-push (push) Successful in 54s

Add more toast types
This commit is contained in:
2026-05-11 13:22:42 +02:00
parent 4e3b0ddb08
commit f82c61ef1e
18 changed files with 1026 additions and 109 deletions
@@ -8,17 +8,22 @@
this.status = newStatus;
this.status_display = newStatusDisplay;
this.saving = true;
fetch(`/api/games/{{ game.id }}/status`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token }}'
},
body: JSON.stringify({ status: newStatus })
}).then(() => {
document.body.dispatchEvent(new CustomEvent('status-changed'));
})
.finally(() => this.saving = false);
// TODO: migrate to hx-post + hx-on::after-request for HTMX-native toast handling
fetchWithHtmxTriggers(`/api/games/{{ game.id }}/status`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token }}'
},
body: JSON.stringify({ status: newStatus })
})
.then(() => {
document.body.dispatchEvent(new CustomEvent('status-changed'));
})
.catch(() => {
console.error('Failed to update status');
})
.finally(() => this.saving = false);
}
}"
>
@@ -41,5 +46,4 @@
</div>
</button>
</div>
<div x-show="saving" style="display: none;">Saving...</div>
</div>
@@ -1,11 +1,11 @@
<div id="refund-confirmation-modal" class="fixed inset-0 bg-black/70 dark:bg-gray-600/50 overflow-y-auto h-full w-full flex items-center justify-center">
<div class="relative mx-auto p-5 border-accent border w-full max-w-md shadow-lg/50 rounded-md bg-white dark:bg-gray-900">
<div class="">
<h1 class="text-2xl leading-6 font-medium dark:text-white text-center">Confirm Refund</h3>
<h1 class="text-2xl leading-6 font-medium dark:text-white text-center">Confirm Refund</h1>
<p class="dark:text-white text-center mt-5">
Are you sure you want to mark this purchase as refunded?
</p>
<form class="" hx-post="{% url 'refund_purchase' purchase_id %}" hx-target="#global-modal-container" hx-swap="innerHTML">
<form class="" hx-post="{% url 'refund_purchase' purchase_id %}" hx-target="#purchase-row-{{ purchase_id }}" hx-swap="outerHTML">
{% csrf_token %}
<div class="mt-5 text-center">
<label class="flex flex-row items-center justify-center align-baseline gap-5">
@@ -6,34 +6,29 @@
deviceName: '{{ session.device.name|default:'Unknown'|escapejs }}',
open: false,
saving: false,
error: '',
success: false,
setDevice(newDeviceId, newDeviceName) {
this.deviceId = newDeviceId;
this.deviceName = newDeviceName;
this.saving = true;
this.error = '';
this.success = false;
fetch(`/api/session/{{ session.id }}/device`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token }}'
},
body: JSON.stringify({ device_id: newDeviceId })
})
.then(() => {
this.success = true;
this.error = '';
document.body.dispatchEvent(new CustomEvent('device-changed'));
})
.catch(() => {
this.error = 'Failed to update device';
this.deviceName = this.originalDeviceName;
this.deviceId = this.originalDeviceId;
})
.finally(() => this.saving = false);
}
this.deviceId = newDeviceId;
this.deviceName = newDeviceName;
this.saving = true;
// TODO: migrate to hx-post + hx-on::after-request for HTMX-native toast handling
fetchWithHtmxTriggers(`/api/session/{{ session.id }}/device`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token }}'
},
body: JSON.stringify({ device_id: newDeviceId })
})
.then((res) => {
document.body.dispatchEvent(new CustomEvent('device-changed'));
})
.catch(() => {
this.deviceName = this.originalDeviceName;
this.deviceId = this.originalDeviceId;
console.error('Failed to update device');
})
.finally(() => this.saving = false);
}
}"
>
<div class="inline-flex rounded-md shadow-2xs" role="group" @click.outside="open = false">
@@ -51,6 +46,4 @@
</div>
</button>
</div>
<div x-show="success" class="text-xs text-green-600 dark:text-green-400" style="display: none;">Saved</div>
<div x-show="error" x-text="error" class="text-xs text-red-600 dark:text-red-400" style="display: none;"></div>
</div>