chartManD commited on
Commit
e49f021
·
1 Parent(s): 97b228f

Correccion de GET en fase 3 de PF

Browse files
tecnicas/controllers/models_controller/escala_controller.py CHANGED
@@ -7,19 +7,25 @@ class EscalaController():
7
  scale: Escala
8
  tags_relation: dict[str, EtiquetasEscala]
9
 
10
- def __init__(self, data):
11
- self.scale = Escala(
12
- id_tipo_escala=TipoEscala.objects.get(id=data["id_scale"]),
13
- longitud=data["size"],
14
- tecnica=data["technique"]
15
- )
16
-
17
- def setScale(self, newData):
18
- self.scale = Escala(
19
- id_tipo_escala=TipoEscala.objects.get(id=newData["id_scale"]),
20
- longitud=newData["size"],
21
- tecnica=newData["technique"]
22
- )
 
 
 
 
 
 
23
 
24
  def saveScale(self):
25
  try:
 
7
  scale: Escala
8
  tags_relation: dict[str, EtiquetasEscala]
9
 
10
+ def __init__(self, data, use_scale: Escala = None):
11
+ if use_scale:
12
+ self.scale = use_scale
13
+ else:
14
+ self.scale = Escala(
15
+ id_tipo_escala=TipoEscala.objects.get(id=data["id_scale"]),
16
+ longitud=data["size"],
17
+ tecnica=data["technique"]
18
+ )
19
+
20
+ def setScale(self, newData, use_scale: Escala):
21
+ if use_scale:
22
+ self.scale = use_scale
23
+ else:
24
+ self.scale = Escala(
25
+ id_tipo_escala=TipoEscala.objects.get(id=data["id_scale"]),
26
+ longitud=data["size"],
27
+ tecnica=data["technique"]
28
+ )
29
 
30
  def saveScale(self):
31
  try:
tecnicas/controllers/views_controller/create_session/panel_basic_controller.py CHANGED
@@ -167,15 +167,12 @@ class PanelBasicController():
167
  print(form.cleaned_data)
168
  values = {}
169
  for name, value in form.cleaned_data.items():
170
- if name == "tipo_escala":
171
- values[name] = value.id
172
- else:
173
- values[name] = value
174
 
175
  values["name_tecnica"] = name_tecnica
176
  request.session['form_basic'] = values
177
  response = redirect(
178
- reverse(PanelBasicController.url_next_panel_tags))
179
  else:
180
  response = render(request, PanelBasicController.url_panel_basic_pf, {
181
  "form_sesion": form, "error": "Información no valida"})
 
167
  print(form.cleaned_data)
168
  values = {}
169
  for name, value in form.cleaned_data.items():
170
+ values[name] = value
 
 
 
171
 
172
  values["name_tecnica"] = name_tecnica
173
  request.session['form_basic'] = values
174
  response = redirect(
175
+ reverse(PanelBasicController.url_next_panel_codes))
176
  else:
177
  response = render(request, PanelBasicController.url_panel_basic_pf, {
178
  "form_sesion": form, "error": "Información no valida"})
tecnicas/controllers/views_controller/create_session/panel_codes_controller.py CHANGED
@@ -80,7 +80,7 @@ class PanelCodesController():
80
  return render(request, PanelCodesController.url_current_panel, context_codes_form)
81
 
82
  @staticmethod
83
- def controllPostRATA(request: HttpRequest, is_rata: True):
84
  codes = []
85
  context_codes_form = {}
86
 
 
80
  return render(request, PanelCodesController.url_current_panel, context_codes_form)
81
 
82
  @staticmethod
83
+ def controllPostRATA(request: HttpRequest, is_rata=True):
84
  codes = []
85
  context_codes_form = {}
86
 
tecnicas/controllers/views_controller/create_session/panel_create_controller.py CHANGED
@@ -2,7 +2,7 @@ from django.http import HttpRequest, JsonResponse
2
  from django.db import transaction
3
  from django.shortcuts import render
4
  from tecnicas.utils import general_error
5
- from tecnicas.models import EsAtributo, EsVocabulario, Vocabulario, Tecnica, TipoTecnica, EstiloPalabra, Producto, Palabra, SesionSensorial
6
  from tecnicas.controllers import TecnicaController, EscalaController, ProductosController, OrdenesController, EstiloPalabrasController, PalabrasController, SesionController
7
  from tecnicas.utils import deleteDataSession
8
 
@@ -289,9 +289,9 @@ class PanelCreateController():
289
  #
290
  # //////////////////////////////////////////////////////// #
291
  session = SesionSensorial.objects.create(
292
- name_session=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None,
293
- technique=technique,
294
- creator=request.user.user_presentador
295
  )
296
 
297
  if not session:
@@ -448,48 +448,41 @@ class PanelCreateController():
448
  @staticmethod
449
  def controllPostPF(request: HttpRequest):
450
  if request.POST.get('action') == 'create_session':
451
- if not request.session.get("form_codes") or not request.session.get("form_tags"):
452
  deleteDataSession(request)
453
  return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo")
454
  try:
455
  with transaction.atomic():
456
- # ////////////////////////////////////////////////////// #
457
  #
458
- # First step: Create technique and scale with their tags #
459
  #
460
- # ////////////////////////////////////////////////////// #
461
  data_basic = request.session["form_basic"]
462
- data_basic["numero_repeticiones"] = 0
463
 
464
  technique = Tecnica.objects.create(
465
  tipo_tecnica=TipoTecnica.objects.get(
466
  nombre_tecnica=data_basic["name_tecnica"]),
467
  id_estilo=EstiloPalabra.objects.get(
468
  nombre_estilo="vocabulario"),
469
- repeticiones_max=data_basic["numero_repeticiones"],
470
  limite_catadores=data_basic["numero_catadores"],
471
- instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador",
472
  )
473
 
474
  if not technique:
475
  raise ValueError("Error al guardar la técnica")
476
 
477
- data_scale = {
478
- "id_scale": data_basic["tipo_escala"],
479
- "size": data_basic["tamano_escala"],
480
- "technique": technique
481
- }
482
-
483
- controllerScale = EscalaController(data=data_scale)
484
-
485
- scale = controllerScale.saveScale()
486
- if isinstance(scale, dict):
487
- raise ValueError(scale["error"])
488
-
489
- dict_tags = request.session["form_tags"]
490
- saved_related_tags = controllerScale.realteTags(dict_tags)
491
- if "error" in saved_related_tags:
492
- raise ValueError(saved_related_tags["error"])
493
 
494
  # ////////////////////////////////////////////// #
495
  #
 
2
  from django.db import transaction
3
  from django.shortcuts import render
4
  from tecnicas.utils import general_error
5
+ from tecnicas.models import EsAtributo, EsVocabulario, Vocabulario, Tecnica, TipoTecnica, EstiloPalabra, Producto, Palabra, SesionSensorial, Escala, TipoEscala, EtiquetasEscala
6
  from tecnicas.controllers import TecnicaController, EscalaController, ProductosController, OrdenesController, EstiloPalabrasController, PalabrasController, SesionController
7
  from tecnicas.utils import deleteDataSession
8
 
 
289
  #
290
  # //////////////////////////////////////////////////////// #
291
  session = SesionSensorial.objects.create(
292
+ nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else "",
293
+ tecnica=technique,
294
+ creadoPor=request.user.user_presentador
295
  )
296
 
297
  if not session:
 
448
  @staticmethod
449
  def controllPostPF(request: HttpRequest):
450
  if request.POST.get('action') == 'create_session':
451
+ if not request.session.get("form_codes"):
452
  deleteDataSession(request)
453
  return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo")
454
  try:
455
  with transaction.atomic():
456
+ # ////////////////////////////////////// #
457
  #
458
+ # First step: Create technique and scale #
459
  #
460
+ # ////////////////////////////////////// #
461
  data_basic = request.session["form_basic"]
462
+ phases_before_reptition = 2
463
 
464
  technique = Tecnica.objects.create(
465
  tipo_tecnica=TipoTecnica.objects.get(
466
  nombre_tecnica=data_basic["name_tecnica"]),
467
  id_estilo=EstiloPalabra.objects.get(
468
  nombre_estilo="vocabulario"),
469
+ repeticiones_max=data_basic["numero_repeticiones"] + phases_before_reptition,
470
  limite_catadores=data_basic["numero_catadores"],
471
+ instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Analista",
472
  )
473
 
474
  if not technique:
475
  raise ValueError("Error al guardar la técnica")
476
 
477
+ created_scale = Escala.objects.create(
478
+ id_tipo_escala=TipoEscala.objects.get(
479
+ nombre_escala="estructurada"),
480
+ longitud=data_basic["numero_productos"],
481
+ tecnica=technique
482
+ )
483
+
484
+ if not created_scale:
485
+ raise ValueError("No se ha podido crear la escala")
 
 
 
 
 
 
 
486
 
487
  # ////////////////////////////////////////////// #
488
  #
tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_pf_controller.py CHANGED
@@ -1,13 +1,15 @@
1
  from django.http import HttpRequest
2
  from django.shortcuts import redirect, render
3
  from django.urls import reverse
4
- from tecnicas.models import Producto, Participacion, Palabra, Calificacion, ListaPalabras
5
  from tecnicas.controllers import ParticipacionController, PalabrasController, EscalaController
6
  from tecnicas.forms import ListWordsForm
7
  from .general_test_controller import GenetalTestController
8
 
9
 
10
  class TestPFController(GenetalTestController):
 
 
11
  def __init__(self, sensorial_session, user_tester):
12
  super().__init__(sensorial_session, user_tester)
13
 
@@ -104,80 +106,64 @@ class TestPFController(GenetalTestController):
104
  return render(request, self.current_directory, self.context)
105
 
106
  def getRepetitionPhase(self, request: HttpRequest):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  technique = self.session.tecnica
108
 
 
109
  products_in_technique = Producto.objects.filter(id_tecnica=technique)
110
 
111
- words = list(
112
- ListaPalabras.objects.get(
 
113
  tecnica=self.session.tecnica,
114
  catador=request.user.user_catador,
115
  es_final=True
116
- ).palabras.all()
117
- )
118
-
119
- use_product: Producto = None
120
- use_words: list[Palabra] = None
121
-
122
- # Revisamos el producto que le falten calificaciones
123
- for current_product in products_in_technique:
124
- try:
125
- rating = Calificacion.objects.get(
126
- num_repeticion=technique.repeticion,
127
- id_producto=current_product,
128
- id_tecnica=technique,
129
- id_catador=self.tester
130
- )
131
- except Calificacion.DoesNotExist:
132
- # Si no hay calificacion mandamos el producto actual y todas la palabras
133
- use_product = current_product
134
- use_words = words
135
- break
136
 
137
- # Obtener los datos asociados para la calificacion para ver que palabras quedan por calificar
138
- recoreded_data = rating.dato_calificacion.all()
139
 
140
- if not recoreded_data:
141
- # Si no hay datos entonces devolver el producto con todas las palabras
142
- use_product = current_product
143
- use_words = words
144
- break
145
- else:
146
- words_to_use = PalabrasController.getWordsWithoutData(
147
- recoreded_data=recoreded_data, words=words)
148
-
149
- # Si quedan palabras por calificar mandar las palabras con el producto
150
- if not isinstance(words_to_use, dict) and words_to_use:
151
- use_product = current_product
152
- use_words = words_to_use
153
- break
154
-
155
- # Si no hay producto que falta por calificar finalizar sesion para el Catador
156
- if not use_product:
157
- updated_participation = ParticipacionController.finishSession(
158
- self.participation)
159
- params = {
160
- "code_sesion": self.session.codigo_sesion
161
- }
162
- return redirect(reverse(self.previus_directory, kwargs=params))
163
 
164
- scale = EscalaController.getScaleByTechnique(technique=technique)
165
- use_tags = EscalaController.getRelatedTagsInScale(scale=scale)
166
-
167
- self.context["product"] = use_product
168
- self.context["words"] = use_words
169
-
170
- self.context["scale"] = scale
171
- self.context["type_scale"] = scale.id_tipo_escala.nombre_escala
172
- self.context["tags"] = use_tags
173
 
174
- self.context["repetition"] = technique.repeticion - 2
 
 
 
 
 
175
 
176
- if self.context["type_scale"] == "continua":
177
- self.context["size_scale"] = {
178
- "max_size": scale.longitud * 100,
179
- "middle_size": (scale.longitud * 100)/2
180
- }
181
 
182
  return render(request, self.current_directory, self.context)
183
 
 
1
  from django.http import HttpRequest
2
  from django.shortcuts import redirect, render
3
  from django.urls import reverse
4
+ from tecnicas.models import Producto, Participacion, Palabra, Calificacion, ListaPalabras, Dato
5
  from tecnicas.controllers import ParticipacionController, PalabrasController, EscalaController
6
  from tecnicas.forms import ListWordsForm
7
  from .general_test_controller import GenetalTestController
8
 
9
 
10
  class TestPFController(GenetalTestController):
11
+ skip_phases = 2
12
+
13
  def __init__(self, sensorial_session, user_tester):
14
  super().__init__(sensorial_session, user_tester)
15
 
 
106
  return render(request, self.current_directory, self.context)
107
 
108
  def getRepetitionPhase(self, request: HttpRequest):
109
+ '''
110
+ - Obtener todos los productos que se evaluan en la tecnica
111
+ - Obtener todas las palabras de la lista de palabras del catador
112
+ - Para cada palabra, comprobar que el numero de Dato sea igual al numero de Productos
113
+ - Si no hay datos mandar esa palabra por contexto con todos los productos
114
+ - De las palabras que falten tomar la primera y mandarla en el contexto
115
+ - Mandar todos los productos por el contexto
116
+ Nota: Para esta fase no hay necesidad de mandar una escala, la escala se creara en el cliente
117
+ '''
118
+ self.participation.refresh_from_db()
119
+
120
+ if self.participation.finalizado:
121
+ params = {"code_sesion": self.session.codigo_sesion}
122
+ return redirect(reverse(self.previus_directory, kwargs=params))
123
+
124
  technique = self.session.tecnica
125
 
126
+ # Obtener todos los productos que se evaluan en la técnica
127
  products_in_technique = Producto.objects.filter(id_tecnica=technique)
128
 
129
+ # Obtener todas las palabras de la lista del catador (preferir lista final)
130
+ try:
131
+ words = list(ListaPalabras.objects.get(
132
  tecnica=self.session.tecnica,
133
  catador=request.user.user_catador,
134
  es_final=True
135
+ ).palabras.all())
136
+ except ListaPalabras.DoesNotExist:
137
+ words = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
+ use_word: Palabra = None
 
140
 
141
+ # Revisar que palabra no ha sido calificada en todos los productos
142
+ for word in words:
143
+ current_num_data = Dato.objects.filter(
144
+ id_calificacion__num_repeticion=technique.repeticion,
145
+ id_calificacion__id_tecnica=technique,
146
+ id_calificacion__id_catador=request.user.user_catador,
147
+ id_palabra=word
148
+ ).count()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
 
150
+ if not current_num_data:
151
+ use_word = word
152
+ break
153
+ elif current_num_data < len(products_in_technique):
154
+ self.context["error"] = "Se ha detectado una inconsistencia en los datos que se deben calificar, algunos productos no han sido calificados"
155
+ return render(request, self.current_directory, self.context)
 
 
 
156
 
157
+ if not use_word:
158
+ self.participation = Participacion.objects.get(
159
+ tecnica=self.session.tecnica, catador=request.user.user_catador)
160
+ ParticipacionController.finishSession(self.participation)
161
+ params = {"code_sesion": self.session.codigo_sesion}
162
+ return redirect(reverse(self.previus_directory, kwargs=params))
163
 
164
+ self.context["word"] = use_word
165
+ self.context["products"] = products_in_technique
166
+ self.context["repetition"] = technique.repeticion - self.skip_phases
 
 
167
 
168
  return render(request, self.current_directory, self.context)
169
 
tecnicas/forms/create_session/sesion_basic_pf_form.py CHANGED
@@ -19,18 +19,12 @@ class SesionBasicPFForm(forms.Form):
19
  "placeholder": "Solo números"
20
  }), required=True)
21
 
 
 
 
 
 
22
  instrucciones = forms.CharField(max_length=255, widget=forms.TextInput(attrs={
23
  "class": "bg-surface-ligt border-b-1 text-center w-full p-1",
24
  "placeholder": "Este campo es opcional"
25
  }), required=False)
26
-
27
- def __init__(self, *args, **kwargs):
28
- super().__init__(*args, **kwargs)
29
-
30
- self.fields['tipo_escala'] = forms.ModelChoiceField(queryset=TipoEscala.objects.all(), widget=forms.RadioSelect(attrs={
31
- "class": "uppercase text-lg tracking-wider font-medium p-2 px-4 active:px-5 transition-all rounded-xl bg-blue-500 text-white",
32
- }), required=True, initial=TipoEscala.objects.first())
33
-
34
- self.fields['tamano_escala'] = forms.IntegerField(widget=forms.HiddenInput(attrs={
35
- "class": "cts-size-input",
36
- }), required=True)
 
19
  "placeholder": "Solo números"
20
  }), required=True)
21
 
22
+ numero_repeticiones = forms.IntegerField(widget=forms.NumberInput(attrs={
23
+ "class": "bg-surface-ligt p-1 border-b-1 text-center w-full",
24
+ "placeholder": "Solo números"
25
+ }), required=True)
26
+
27
  instrucciones = forms.CharField(max_length=255, widget=forms.TextInput(attrs={
28
  "class": "bg-surface-ligt border-b-1 text-center w-full p-1",
29
  "placeholder": "Este campo es opcional"
30
  }), required=False)
 
 
 
 
 
 
 
 
 
 
 
tecnicas/templates/tecnicas/create_sesion/panel-basic-pf.html CHANGED
@@ -41,6 +41,13 @@
41
  </p>
42
  {{ form_sesion.numero_catadores }}
43
  </label>
 
 
 
 
 
 
 
44
  </section>
45
  <section class="flex justify-center items-center mt-2">
46
  <label for="{{form_sesion.instrucciones.id_for_label}}"
@@ -51,55 +58,6 @@
51
  </section>
52
  </article>
53
 
54
- <article class="cs-escalas-radio flex flex-col gap-4">
55
- <h2 class="text-2xl font-bold">Selecciona una escala</h2>
56
- <section class="flex flex-row gap-4 justify-around flex-wrap">
57
- {% for escala in form_sesion.tipo_escala %}
58
- <label for="{{escala.id_for_label}}"
59
- class="ct-radio-escala uppercase text-lg tracking-wider font-bold p-2 px-4 rounded-xl cts-btn-primary btn-push">
60
- {{ escala.tag }}
61
- {{ escala.choice_label }}
62
- </label>
63
- {% endfor %}
64
- {% if form_sesion.tipo_escala.errors %}
65
- <div class="w-full text-center text-red-600 text-xl font-medium tracking-wide">
66
- {{ form_sesion.tipo_escala.errors }}
67
- </div>
68
- {% endif %}
69
- </section>
70
-
71
- <section class="py-2 px-5 flex flex-col justify-center items-center gap-2 relative">
72
- <label for="{{ form_sesion.tamano_escala.id_for_label }}"
73
- class="ct-size-scale text-xl flex flex-col items-center px-2 font-bold">
74
- <p>Establece número de segmentos:</p>
75
- {{ form_sesion.tamano_escala }}
76
- </label>
77
- <div class="flex justify-around max-sm:flex-col gap-8 cts-options-size-scale">
78
- <label class="flex flex-col items-center cursor-pointer">
79
- <input type="radio" name="option_size_scale" value="5"
80
- class="radio radio-lg checked:bg-pink-500" />
81
- <span class="mt-2 text-xl text-gray-700 font-medium">5</span>
82
- </label>
83
- <label class="flex flex-col items-center cursor-pointer">
84
- <input type="radio" name="option_size_scale" value="7"
85
- class="radio radio-lg checked:bg-pink-500" />
86
- <span class="mt-2 text-xl text-gray-700 font-medium">7</span>
87
- </label>
88
- <label class="flex flex-col items-center cursor-pointer">
89
- <input type="radio" name="option_size_scale" value="9"
90
- class="radio radio-lg checked:bg-pink-500" />
91
- <span class="mt-2 text-xl text-gray-700 font-medium">9</span>
92
- </label>
93
- </div>
94
- {% if form_sesion.tamano_escala.errors %}
95
- <article
96
- class="w-fit rounded px-2 py-0.5 text-center text-white text-sm font-medium tracking-wide bg-red-500">
97
- {{ form_sesion.tamano_escala.errors }}
98
- </article>
99
- {% endif %}
100
- </section>
101
- </article>
102
-
103
  <article class="w-full flex max-sm:flex-col flex-wrap items-center justify-center gap-4">
104
  <button type="submit" class="cts-btn-general cts-btn-primary btn-push flex-1/4 w-full">
105
  Continuar
 
41
  </p>
42
  {{ form_sesion.numero_catadores }}
43
  </label>
44
+ <label for="{{ form_sesion.numero_repeticiones.id_for_label }}"
45
+ class="text-lg flex flex-col items-center px-2 font-medium tracking-wide">
46
+ <p class="tracking-normal text-base font-bold">
47
+ Número de repeticiones:
48
+ </p>
49
+ {{ form_sesion.numero_repeticiones }}
50
+ </label>
51
  </section>
52
  <section class="flex justify-center items-center mt-2">
53
  <label for="{{form_sesion.instrucciones.id_for_label}}"
 
58
  </section>
59
  </article>
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  <article class="w-full flex max-sm:flex-col flex-wrap items-center justify-center gap-4">
62
  <button type="submit" class="cts-btn-general cts-btn-primary btn-push flex-1/4 w-full">
63
  Continuar
tecnicas/templates/tecnicas/forms_tester/test_pf_rating_list.html CHANGED
@@ -73,20 +73,11 @@
73
  Fase <span class="cts-phase-pf" data-phase="3">3</span>:
74
  </p>
75
  <p class="text-xl font-bold text-center">
76
- Calificación de listas
77
  </p>
78
  </section>
79
 
80
  <section class="flex items-center justify-center flex-wrap gap-4">
81
- <div class="bg-surface-ligt p-2 rounded-lg flex-1">
82
- <p class="text-lg font-bold text-center">
83
- Producto:
84
- </p>
85
- <p class="text-2xl font-bold text-center ct-product-rating">
86
- <span class="code-product">{{ product }}</span>
87
- <span class="hidden id-product">{{ product.id }}</span>
88
- </p>
89
- </div>
90
  <div class="bg-surface-ligt p-2 rounded-lg flex-1">
91
  <p class="text-lg font-bold text-center">
92
  Repetición:
@@ -105,25 +96,21 @@
105
  </section>
106
  </article>
107
 
108
- <article
109
- class="scales-container [&>*:not(:last-child)]:mb-5 min-lg:grid min-lg:items-start grid-cols-2 gap-3 justify-center items-center">
110
- {% with path_con="../components/form-scale-continue.html" path_str="../components/form-scale-structure.html" %}
111
- {% if type_scale == "continua" %}
112
- {% for word in words %}
113
- {% include path_con with word=word tags=tags scale=scale size_scale=size_scale %}
114
- {% endfor %}
115
- {% elif type_scale == "estructurada" %}
116
- {% for word in words %}
117
- {% include path_str with word=word tags=tags scale=scale %}
118
  {% endfor %}
119
- {% endif %}
120
- {% endwith %}
121
  </article>
122
  </article>
123
  </article>
124
  {% endblock %}
125
 
126
  {% block extra_js %}
127
- <script src="{% static 'js/created-scale.js' %}"></script>
128
  <script src="{% static 'js/actions-form.js' %}"></script>
129
  {% endblock %}
 
73
  Fase <span class="cts-phase-pf" data-phase="3">3</span>:
74
  </p>
75
  <p class="text-xl font-bold text-center">
76
+ Evaluación de Atributos
77
  </p>
78
  </section>
79
 
80
  <section class="flex items-center justify-center flex-wrap gap-4">
 
 
 
 
 
 
 
 
 
81
  <div class="bg-surface-ligt p-2 rounded-lg flex-1">
82
  <p class="text-lg font-bold text-center">
83
  Repetición:
 
96
  </section>
97
  </article>
98
 
99
+ <article class="rounded flex flex-col gap-4">
100
+ <p>Palabra a evaluar: {{ word }}</p>
101
+ <div>
102
+ <p>Productos a ordenar:</p>
103
+ <ul>
104
+ {% for product in products %}
105
+ <li>{{ product }}</li>
 
 
 
106
  {% endfor %}
107
+ </ul>
108
+ </div>
109
  </article>
110
  </article>
111
  </article>
112
  {% endblock %}
113
 
114
  {% block extra_js %}
 
115
  <script src="{% static 'js/actions-form.js' %}"></script>
116
  {% endblock %}