Fase 3 (isla): recuperar ítems (restore_items) en React/TSX, flujo de 2 pasos

restore_items_view ahora responde JSON cuando la petición es AJAX (X-Requested-With):
GET con character_name -> {items}; POST recover_id -> {success, message}. Se conserva
el flujo legacy (redirect+messages) para no-AJAX. RestoreItemsForm.tsx: paso 1 elegir
personaje y buscar ítems borrados (SOAP), paso 2 elegir ítem y recuperarlo; refresca la
lista tras recuperar. La vista pasa character_names por json_script.

Verificado: check OK, render de la isla, redirige a login sin sesión.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-12 22:01:19 +00:00
parent 08c36619f0
commit 68cfe7594b
5 changed files with 169 additions and 35 deletions
+8 -29
View File
@@ -17,35 +17,14 @@
<p>Se pueden consultar ítems borrados en un mismo personaje cada 8 horas.</p>
</fieldset>
<!-- Selección de personaje -->
<form method="GET" action="{% url 'restore-items' %}">
<label for="character_name">Selecciona un personaje:</label>
<select name="character_name" id="character_name" required>
<option value="" disabled selected>Selecciona un personaje</option>
{% for character in characters %}
<option value="{{ character }}" {% if character == selected_character %}selected{% endif %}>{{ character }}</option>
{% endfor %}
</select>
<button type="submit">Buscar Ítems Eliminados</button>
</form>
{% if deleted_items %}
<form method="POST" action="{% url 'restore-items' %}">
{% csrf_token %}
<input type="hidden" name="character_name" value="{{ selected_character }}">
<label for="recover_id">Selecciona un ítem para restaurar:</label>
<select name="recover_id" id="recover_id" required>
{% for item in deleted_items %}
<option value="{{ item.recover_id }}">
Item: {{ item.item_name }} ({{ item.item_id }}):{{ item.count }}
</option>
{% endfor %}
</select>
<button type="submit">Recuperar Ítem</button>
</form>
{% elif selected_character %}
<p>No hay ítems eliminados disponibles para restaurar.</p>
{% endif %}
{% load django_vite %}
<!-- Isla React (Vite): recuperar ítems borrados (2 pasos vía AJAX:
buscar ítems del personaje -> recuperar el elegido). -->
<div id="restore-items-app"
data-csrf="{{ csrf_token }}"
data-url="{% url 'restore-items' %}"></div>
{{ character_names|json_script:"restore-items-data" }}
{% vite_asset 'src/entries/restore_items.tsx' %}
</div>
</div>
</div>
+22 -6
View File
@@ -204,6 +204,9 @@ def restore_items_view(request):
except Exception as e:
messages.error(request, f"Error al obtener los personajes: {str(e)}")
# La isla React usa AJAX (X-Requested-With); en ese caso respondemos JSON.
is_ajax = request.headers.get('X-Requested-With') == 'XMLHttpRequest'
if request.method == "GET" and "character_name" in request.GET:
selected_character = request.GET.get("character_name")
@@ -229,13 +232,20 @@ def restore_items_view(request):
})
except Exception as e:
if is_ajax:
return JsonResponse({'error': f'Error al obtener los ítems eliminados: {str(e)}'})
messages.error(request, f"Error al obtener los ítems eliminados: {str(e)}")
if is_ajax:
return JsonResponse({'items': deleted_items})
if request.method == "POST":
recover_id = request.POST.get("recover_id")
selected_character = request.POST.get("character_name")
if not recover_id or not selected_character:
if is_ajax:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Selecciona un personaje y un ítem para restaurar.</span>'})
messages.error(request, "Selecciona un personaje y un ítem para restaurar.")
return redirect('restore-items')
@@ -243,20 +253,26 @@ def restore_items_view(request):
# Ejecutar comando SOAP para restaurar el ítem
command = f".item restore {recover_id} {selected_character}"
response = execute_soap_command(command)
if "success" in response.lower():
messages.success(request, "Ítem restaurado exitosamente.")
else:
messages.error(request, "No se pudo restaurar el ítem.")
ok = "success" in response.lower()
except Exception as e:
if is_ajax:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al restaurar el ítem: {str(e)}</span>'})
messages.error(request, f"Error al restaurar el ítem: {str(e)}")
return redirect('restore-items')
if is_ajax:
msg = ('<span class="ok-form-response">Ítem restaurado exitosamente.</span>' if ok
else '<span class="red-form-response">No se pudo restaurar el ítem.</span>')
return JsonResponse({'success': ok, 'message': msg})
messages.success(request, "Ítem restaurado exitosamente.") if ok else messages.error(request, "No se pudo restaurar el ítem.")
return redirect('restore-items')
return render(request, 'account/restore_items.html', {
'characters': characters,
'deleted_items': deleted_items,
'selected_character': selected_character
'selected_character': selected_character,
'character_names': characters,
})
def quest_character_view(request):
username = request.session.get('username')