Add confirmation before deleting game
This commit is contained in:
+8
-75
@@ -1288,75 +1288,6 @@
|
||||
.box-border {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.form-checkbox {
|
||||
appearance: none;
|
||||
padding: 0;
|
||||
print-color-adjust: exact;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background-origin: border-box;
|
||||
user-select: none;
|
||||
flex-shrink: 0;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
color: oklch(54.6% 0.245 262.881);
|
||||
background-color: #fff;
|
||||
border-color: oklch(55.1% 0.027 264.364);
|
||||
border-width: 1px;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
border-radius: 0px;
|
||||
&:focus {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
--tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
|
||||
--tw-ring-offset-width: 2px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: oklch(54.6% 0.245 262.881);
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
&:checked {
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
&:checked {
|
||||
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
|
||||
@media (forced-colors: active) {
|
||||
appearance: auto;
|
||||
}
|
||||
}
|
||||
&:checked:hover {
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
}
|
||||
&:checked:focus {
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
}
|
||||
&:indeterminate {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
@media (forced-colors: active) {
|
||||
appearance: auto;
|
||||
}
|
||||
}
|
||||
&:indeterminate:hover {
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
}
|
||||
&:indeterminate:focus {
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
}
|
||||
}
|
||||
.datatable-pagination-list-item-link {
|
||||
.datatable-wrapper .datatable-bottom .datatable-pagination & {
|
||||
display: flex;
|
||||
@@ -2406,9 +2337,6 @@
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
.align-baseline {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
.align-middle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
@@ -2599,9 +2527,6 @@
|
||||
.text-blue-500 {
|
||||
color: var(--color-blue-500);
|
||||
}
|
||||
.text-blue-600 {
|
||||
color: var(--color-blue-600);
|
||||
}
|
||||
.text-blue-800 {
|
||||
color: var(--color-blue-800);
|
||||
}
|
||||
@@ -2653,6 +2578,9 @@
|
||||
.text-red-500 {
|
||||
color: var(--color-red-500);
|
||||
}
|
||||
.text-red-600 {
|
||||
color: var(--color-red-600);
|
||||
}
|
||||
.text-red-800 {
|
||||
color: var(--color-red-800);
|
||||
}
|
||||
@@ -3615,6 +3543,11 @@
|
||||
color: var(--color-red-200);
|
||||
}
|
||||
}
|
||||
.dark\:text-red-400 {
|
||||
&:is(.dark *) {
|
||||
color: var(--color-red-400);
|
||||
}
|
||||
}
|
||||
.dark\:text-red-500 {
|
||||
&:is(.dark *) {
|
||||
color: var(--color-red-500);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<c-vars color="blue" size="base" type="button" />
|
||||
<button
|
||||
{% if hx_get %}hx_get="{{ hx_get }}"{% endif %}
|
||||
{% if hx_target %}hx_target="{{ hx_target }}"{% endif %}
|
||||
{% if hx_swap %}hx_swap="{{ hx_swap }}"{% endif %}
|
||||
{% if hx_get %}hx-get="{{ hx_get }}"{% endif %}
|
||||
{% if hx_target %}hx-target="{{ hx_target }}"{% endif %}
|
||||
{% if hx_swap %}hx-swap="{{ hx_swap }}"{% endif %}
|
||||
{% if type %}type="{{ type }}"{% endif %}
|
||||
{% if title %}title="{{ title }}"{% endif %}
|
||||
{% if onclick %}onclick="{{ onclick }}"{% endif %}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
alt="loading indicator" />
|
||||
<div class="flex flex-col min-h-screen">
|
||||
{% include "navbar.html" %}
|
||||
<div class="flex flex-1 flex-col pt-8 pb-16">{{ slot }}</div>
|
||||
<div id="main-container" class="flex flex-1 flex-col pt-8 pb-16">{{ slot }}</div>
|
||||
{% load version %}
|
||||
<span class="fixed left-2 bottom-2 text-xs text-slate-300 dark:text-slate-600">{% version %} ({% version_date %})</span>
|
||||
</div>
|
||||
@@ -106,7 +106,8 @@
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<div id="global-modal-container"></div>
|
||||
// hx-swap-oob makes sure the modal gets removed upon any HTMX response
|
||||
<div id="global-modal-container" hx-swap-oob="true"></div>
|
||||
|
||||
<div x-data="toastStore()"
|
||||
role="region"
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<div id="delete-game-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">Delete Game</h1>
|
||||
<p class="dark:text-white text-center mt-5">
|
||||
Are you sure you want to delete <strong>{{ game.name }}</strong>?
|
||||
</p>
|
||||
<form class=""
|
||||
hx-post="{% url 'games:delete_game' game.id %}"
|
||||
hx-replace-url="true"
|
||||
hx-target="#main-container"
|
||||
hx-select="#main-container"
|
||||
hx-swap="outerHTML"
|
||||
hw-swap-oob="#global-modal-container"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<p class="dark:text-white text-center mt-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
This will permanently delete this game and all associated data:
|
||||
</p>
|
||||
<ul class="dark:text-white text-center mt-1 text-sm text-gray-600 dark:text-gray-400 list-disc list-inside">
|
||||
{% if session_count %}<li>{{ session_count }} session(s)</li>{% endif %}
|
||||
{% if purchase_count %}<li>{{ purchase_count }} purchase(s)</li>{% endif %}
|
||||
{% if playevent_count %}<li>{{ playevent_count }} play event(s)</li>{% endif %}
|
||||
{% if not session_count and not purchase_count and not playevent_count %}<li>No associated data</li>{% endif %}
|
||||
</ul>
|
||||
<p class="dark:text-white text-center mt-3 text-sm font-medium text-red-600 dark:text-red-400">
|
||||
This action cannot be undone.
|
||||
</p>
|
||||
<div class="items-center mt-5">
|
||||
<c-button color="red" size="lg" type="submit" class="w-full">Delete</c-button>
|
||||
<c-button color="gray" size="base" class="mt-0 w-full" onclick="this.closest('#delete-game-confirmation-modal').remove()">Cancel</c-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -127,7 +127,7 @@
|
||||
Edit
|
||||
</button>
|
||||
</a>
|
||||
<a href="{% url 'games:delete_game' game.id %}">
|
||||
<a href="#" hx-get="{% url 'games:delete_game_confirmation' game.id %}" hx-target="#global-modal-container">
|
||||
<button type="button"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-e-lg hover:bg-red-100 hover:text-blue-700 focus:z-10 focus:ring-2 focus:ring-blue-700 focus:text-blue-700 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:text-white dark:hover:bg-red-700 dark:focus:ring-blue-500 dark:focus:text-white hover:cursor-pointer">
|
||||
Delete
|
||||
|
||||
@@ -23,6 +23,7 @@ urlpatterns = [
|
||||
path("game/add", game.add_game, name="add_game"),
|
||||
path("game/<int:game_id>/edit", game.edit_game, name="edit_game"),
|
||||
path("game/<int:game_id>/view", game.view_game, name="view_game"),
|
||||
path("game/<int:game_id>/delete/confirm", game.delete_game_confirmation, name="delete_game_confirmation"),
|
||||
path("game/<int:game_id>/delete", game.delete_game, name="delete_game"),
|
||||
path("game/list", game.list_games, name="list_games"),
|
||||
path("platform/add", platform.add_platform, name="add_platform"),
|
||||
|
||||
@@ -165,6 +165,24 @@ def add_game(request: HttpRequest) -> HttpResponse:
|
||||
return render(request, "add_game.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
def delete_game_confirmation(request: HttpRequest, game_id: int) -> HttpResponse:
|
||||
game = get_object_or_404(Game, id=game_id)
|
||||
session_count = game.sessions.count()
|
||||
purchase_count = game.purchases.count()
|
||||
playevent_count = game.playevents.count()
|
||||
return render(
|
||||
request,
|
||||
"partials/delete_game_confirmation.html",
|
||||
{
|
||||
"game": game,
|
||||
"session_count": session_count,
|
||||
"purchase_count": purchase_count,
|
||||
"playevent_count": playevent_count,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def delete_game(request: HttpRequest, game_id: int) -> HttpResponse:
|
||||
game = get_object_or_404(Game, id=game_id)
|
||||
|
||||
Reference in New Issue
Block a user