chartManD commited on
Commit
a4129be
·
1 Parent(s): bf9adb3

Se guarda el progreso de napping con modalidad sort en descripcion

Browse files
tecnicas/controllers/api_controller/rating_napping_controller.py CHANGED
@@ -18,7 +18,6 @@ class RatingNappingController:
18
 
19
  # Branch based on modality
20
  if name_mod == 'sorting':
21
- print(data)
22
  return RatingNappingController.processSortingMode(
23
  data, participation
24
  )
@@ -50,6 +49,8 @@ class RatingNappingController:
50
  RatingNappingController.processGroupsForSorting(
51
  products, groups, participation, existing_ratings_map, products_map
52
  )
 
 
53
 
54
  return JsonResponse({"message": "Datos guardados exitosamente"})
55
 
@@ -163,6 +164,13 @@ class RatingNappingController:
163
  RatingNappingController.processWordsForGroups(
164
  groups, all_groups_for_words
165
  )
 
 
 
 
 
 
 
166
 
167
  @staticmethod
168
  def processWordsForGroups(groups_data, groups_list):
 
18
 
19
  # Branch based on modality
20
  if name_mod == 'sorting':
 
21
  return RatingNappingController.processSortingMode(
22
  data, participation
23
  )
 
49
  RatingNappingController.processGroupsForSorting(
50
  products, groups, participation, existing_ratings_map, products_map
51
  )
52
+ else:
53
+ RatingNappingController.deleteAllGroups(participation)
54
 
55
  return JsonResponse({"message": "Datos guardados exitosamente"})
56
 
 
164
  RatingNappingController.processWordsForGroups(
165
  groups, all_groups_for_words
166
  )
167
+
168
+ @staticmethod
169
+ def deleteAllGroups(participation):
170
+ GrupoProducto.objects.filter(
171
+ tecnica=participation.tecnica,
172
+ catador=participation.catador
173
+ ).delete()
174
 
175
  @staticmethod
176
  def processWordsForGroups(groups_data, groups_list):
tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_napping_controller.py CHANGED
@@ -2,7 +2,7 @@ from django.http import HttpRequest
2
  from django.shortcuts import redirect, render
3
  from django.urls import reverse
4
  from django.db.models import F
5
- from tecnicas.models import Participacion, Producto, TecnicaModalidad, DatoPunto, Calificacion, Modalidad, Palabra
6
  from tecnicas.forms import ListWordsForm
7
  from tecnicas.utils import noValidTechnique
8
  from tecnicas.controllers import ParticipacionController
@@ -90,7 +90,9 @@ class TestNappingController(GenetalTestController):
90
  products_in_technique = Producto.objects.filter(id_tecnica=technique)
91
  self.context["products"] = products_in_technique
92
 
 
93
  self.setCoordinates()
 
94
 
95
  return render(request, self.sort_direction, self.context)
96
 
@@ -114,6 +116,37 @@ class TestNappingController(GenetalTestController):
114
 
115
  self.context["data_points"] = list(data_points)
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  def setWords(self):
118
  technique = self.session.tecnica
119
 
 
2
  from django.shortcuts import redirect, render
3
  from django.urls import reverse
4
  from django.db.models import F
5
+ from tecnicas.models import Participacion, Producto, TecnicaModalidad, DatoPunto, Calificacion, Modalidad, Palabra, GrupoProducto
6
  from tecnicas.forms import ListWordsForm
7
  from tecnicas.utils import noValidTechnique
8
  from tecnicas.controllers import ParticipacionController
 
90
  products_in_technique = Producto.objects.filter(id_tecnica=technique)
91
  self.context["products"] = products_in_technique
92
 
93
+ self.context["form"] = ListWordsForm()
94
  self.setCoordinates()
95
+ self.setGroups()
96
 
97
  return render(request, self.sort_direction, self.context)
98
 
 
116
 
117
  self.context["data_points"] = list(data_points)
118
 
119
+ def setGroups(self):
120
+ technique = self.session.tecnica
121
+
122
+ # Get all product groups for this tester
123
+ grupos_producto = GrupoProducto.objects.filter(
124
+ tecnica=technique,
125
+ catador=self.participation.catador
126
+ ).prefetch_related('productos', 'palabras')
127
+
128
+ groups = []
129
+ for group in grupos_producto:
130
+ # Get products in this group
131
+ products_list = []
132
+ for product in group.productos.all():
133
+ products_list.append({
134
+ 'id': product.id,
135
+ 'codigoProducto': product.codigoProducto
136
+ })
137
+
138
+ # Get words for this group
139
+ words_list = list(group.palabras.values_list(
140
+ 'nombre_palabra', flat=True))
141
+
142
+ groups.append({
143
+ 'id': group.id,
144
+ 'products': products_list,
145
+ 'words': words_list
146
+ })
147
+
148
+ self.context["groups"] = groups
149
+
150
  def setWords(self):
151
  technique = self.session.tecnica
152
 
tecnicas/static/js/test-napping-sort.js CHANGED
@@ -32,6 +32,40 @@ if (isSortMode) {
32
  initSortMode();
33
  }
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  function initSortMode() {
36
  const continueGroupingBtn = document.getElementById('continue-grouping');
37
  const continueDescriptionBtn = document.getElementById('continue-description');
@@ -39,17 +73,50 @@ function initSortMode() {
39
  const dissolveGroupBtn = document.getElementById('dissolve-group-btn');
40
  const groupControls = document.getElementById('group-controls');
41
  const questionSaveBtn = document.getElementById('question-save');
 
42
  const groupWordDialog = document.getElementById('group-word-dialog');
43
  const groupWordForm = document.getElementById('group-word-form');
44
- const groupWordInput = document.querySelector('.cts-input-list-word');
 
45
  const groupWordList = document.getElementById('group-word-list');
46
  const dialogGroupId = document.getElementById('dialog-group-id');
47
 
48
  // Hide question save button initially
49
  questionSaveBtn.classList.add('hidden');
50
 
51
- // Check if there are existing groups from backend (TODO: implement backend data loading)
52
- // For now, start in Phase 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
  // Phase 1: Product Placement
55
  // Show continue to grouping button when all products are placed
@@ -289,7 +356,7 @@ function initSortMode() {
289
  spanNotifaction("Fase de descripción: Haz clic en un grupo para agregar palabras.", false);
290
 
291
  // Auto-save groups when transitioning to Phase 3
292
- window.saveData(false);
293
  }
294
 
295
  // Group Word Dialog Functions
@@ -317,6 +384,7 @@ function initSortMode() {
317
  });
318
 
319
  groupWordList.appendChild(badge);
 
320
  });
321
 
322
  // Update group display with word count
@@ -381,6 +449,39 @@ function initSortMode() {
381
  tooltip.style.maxWidth = '320px';
382
  tooltip.style.whiteSpace = 'normal';
383
  tooltip.classList.remove('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
  }
385
  }
386
 
 
32
  initSortMode();
33
  }
34
 
35
+ function loadExistingGroups() {
36
+ const dataGroupContainer = document.querySelector('.data-group-products');
37
+ if (!dataGroupContainer) return { hasGroups: false, hasWords: false };
38
+
39
+ const groupElements = dataGroupContainer.querySelectorAll('.item-group');
40
+ let hasGroups = false;
41
+ let hasWords = false;
42
+
43
+ groupElements.forEach((groupEl, index) => {
44
+ const groupId = `group-${groupCounter++}`;
45
+ const products = [];
46
+ const words = groupEl.dataset.words ? groupEl.dataset.words.split(',').map(w => w.trim()).filter(w => w) : [];
47
+
48
+ // Get products in this group
49
+ groupEl.querySelectorAll('.item-group-product').forEach(productEl => {
50
+ const code = productEl.dataset.code;
51
+ products.push(code);
52
+ productToGroup[code] = groupId;
53
+ });
54
+
55
+ if (products.length > 0) {
56
+ hasGroups = true;
57
+ productGroups[groupId] = products;
58
+ groupWords[groupId] = words;
59
+
60
+ if (words.length > 0) {
61
+ hasWords = true;
62
+ }
63
+ }
64
+ });
65
+
66
+ return { hasGroups, hasWords };
67
+ }
68
+
69
  function initSortMode() {
70
  const continueGroupingBtn = document.getElementById('continue-grouping');
71
  const continueDescriptionBtn = document.getElementById('continue-description');
 
73
  const dissolveGroupBtn = document.getElementById('dissolve-group-btn');
74
  const groupControls = document.getElementById('group-controls');
75
  const questionSaveBtn = document.getElementById('question-save');
76
+
77
  const groupWordDialog = document.getElementById('group-word-dialog');
78
  const groupWordForm = document.getElementById('group-word-form');
79
+ const groupWordInput = document.getElementsByName('nombre_palabra')[0];
80
+ groupWordInput.value = "";
81
  const groupWordList = document.getElementById('group-word-list');
82
  const dialogGroupId = document.getElementById('dialog-group-id');
83
 
84
  // Hide question save button initially
85
  questionSaveBtn.classList.add('hidden');
86
 
87
+ // Load existing groups from backend and determine initial phase
88
+ const { hasGroups, hasWords } = loadExistingGroups();
89
+
90
+ setTimeout(() => {
91
+ // Determine initial phase based on existing data
92
+ if (hasGroups && hasWords) {
93
+ // Skip to Phase 3 (Description) if groups have words
94
+ currentPhase = 3;
95
+ window.isPlacementActive = false;
96
+ groupControls.classList.remove('hidden');
97
+ continueDescriptionBtn.classList.remove('hidden');
98
+
99
+ renderExistingGroups();
100
+ startDescriptionPhase();
101
+ } else if (hasGroups) {
102
+ // Skip to Phase 2 (Grouping) if groups exist but no words
103
+ currentPhase = 2;
104
+ renderExistingGroups();
105
+ window.isPlacementActive = false;
106
+ groupControls.classList.remove('hidden');
107
+ continueDescriptionBtn.classList.remove('hidden');
108
+
109
+ const plane = document.getElementById('napping-plane');
110
+ plane.classList.remove('cursor-crosshair');
111
+ plane.classList.add('cursor-default');
112
+
113
+ enablePointSelection();
114
+ spanNotifaction("Continúa agrupando productos o pasa a la descripción.", false);
115
+ } else {
116
+ // Start in Phase 1 (Placement)
117
+ currentPhase = 1;
118
+ }
119
+ }, 200);
120
 
121
  // Phase 1: Product Placement
122
  // Show continue to grouping button when all products are placed
 
356
  spanNotifaction("Fase de descripción: Haz clic en un grupo para agregar palabras.", false);
357
 
358
  // Auto-save groups when transitioning to Phase 3
359
+ sortModeSaveData(false);
360
  }
361
 
362
  // Group Word Dialog Functions
 
384
  });
385
 
386
  groupWordList.appendChild(badge);
387
+
388
  });
389
 
390
  // Update group display with word count
 
449
  tooltip.style.maxWidth = '320px';
450
  tooltip.style.whiteSpace = 'normal';
451
  tooltip.classList.remove('hidden');
452
+ } else {
453
+ let tooltip = displayElement.querySelector('.group-tooltip');
454
+ if (tooltip) {
455
+ tooltip.remove();
456
+ }
457
+ }
458
+ }
459
+
460
+ function renderExistingGroups() {
461
+ const colors = ['bg-green-600', 'bg-purple-600', 'bg-yellow-600', 'bg-pink-600', 'bg-indigo-600'];
462
+ let colorIndex = 0;
463
+
464
+ for (const [groupId, products] of Object.entries(productGroups)) {
465
+ const color = colors[colorIndex % colors.length];
466
+ colorIndex++;
467
+
468
+ // Update point colors
469
+ products.forEach(code => {
470
+ const point = document.getElementById(`point-${code}`);
471
+
472
+ if (point) {
473
+ point.classList.remove('bg-red-600');
474
+ point.classList.add(color);
475
+ }
476
+ });
477
+
478
+ // Add group to display
479
+ addGroupToDisplay(groupId, products, color);
480
+
481
+ // Update display with words if they exist
482
+ if (groupWords[groupId] && groupWords[groupId].length > 0) {
483
+ updateGroupDisplayWithWords(groupId);
484
+ }
485
  }
486
  }
487
 
tecnicas/templates/tecnicas/components/dialog-nap-sort.html CHANGED
@@ -1,29 +1,20 @@
1
  <dialog id="group-word-dialog" class="modal">
2
- <div class="modal-box max-w-2xl">
3
  <h3 class="font-bold text-lg">Describir Grupo: <span id="dialog-group-id"></span></h3>
4
  <p class="py-2 text-sm text-gray-600">Agrega palabras para describir este grupo de productos</p>
5
 
6
- <form id="group-word-form" class="space-y-4">
7
- <div class="form-control">
8
- <label class="label">
9
- <span class="label-text">Palabra</span>
10
- </label>
11
- <input type="text" class="cts-input-list-word input input-bordered w-full"
12
- placeholder="Escribe una palabra..." maxlength="50" required>
13
- </div>
14
-
15
- <div class="flex justify-end">
16
- <button type="submit" class="cts-btn-general cts-btn-primary btn-push">
17
- Agregar Palabra
18
- </button>
19
- </div>
20
  </form>
21
 
22
  <div class="mt-4">
23
  <h4 class="font-semibold mb-2">Palabras agregadas:</h4>
24
- <div id="group-word-list" class="flex flex-wrap gap-2">
25
- <!-- Words will be added here dynamically -->
26
- </div>
27
  </div>
28
 
29
  <div class="modal-action">
@@ -32,4 +23,7 @@
32
  </form>
33
  </div>
34
  </div>
 
 
 
35
  </dialog>
 
1
  <dialog id="group-word-dialog" class="modal">
2
+ <div class="modal-box max-w-2xl bg-surface-ligt">
3
  <h3 class="font-bold text-lg">Describir Grupo: <span id="dialog-group-id"></span></h3>
4
  <p class="py-2 text-sm text-gray-600">Agrega palabras para describir este grupo de productos</p>
5
 
6
+ <form id="group-word-form" class="space-y-4 flex justify-center items-center gap-4">
7
+ <label for="{{ form.nombre_palabra.id_for_label }}" class="text-left flex-1">
8
+ {{ form.nombre_palabra }}
9
+ </label>
10
+ <button type="submit" class="cts-btn-general-compress cts-btn-primary btn-push py-1 px-4">
11
+ Agregar
12
+ </button>
 
 
 
 
 
 
 
13
  </form>
14
 
15
  <div class="mt-4">
16
  <h4 class="font-semibold mb-2">Palabras agregadas:</h4>
17
+ <div id="group-word-list" class="flex flex-wrap gap-2"></div>
 
 
18
  </div>
19
 
20
  <div class="modal-action">
 
23
  </form>
24
  </div>
25
  </div>
26
+ <form method="dialog" class="modal-backdrop">
27
+ <button>close</button>
28
+ </form>
29
  </dialog>
tecnicas/templates/tecnicas/forms_tester/test_napping_sort.html CHANGED
@@ -87,6 +87,19 @@
87
  </button>
88
  </div>
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  <!-- Display existing groups -->
91
  <div id="groups-display" class="flex gap-3 flex-wrap justify-center"></div>
92
  </section>
@@ -171,7 +184,7 @@
171
  </section>
172
  </article>
173
 
174
- {% include "../components/dialog-nap-sort.html" %}
175
 
176
  {% include "../components/toast-container.html" %}
177
  </article>
 
87
  </button>
88
  </div>
89
 
90
+ {% if groups %}
91
+ <div class="data-group-products hidden">
92
+ {% for group in groups %}
93
+ <ul class="item-group" {% if group.words %} data-words="{{ group.words|join:',' }}" {% endif %}>
94
+ {% for product in group.products %}
95
+ <li class="item-group-product" data-id-product="{{ product.id }}"
96
+ data-code="{{ product.codigoProducto }}"></li>
97
+ {% endfor %}
98
+ </ul>
99
+ {% endfor %}
100
+ </div>
101
+ {% endif %}
102
+
103
  <!-- Display existing groups -->
104
  <div id="groups-display" class="flex gap-3 flex-wrap justify-center"></div>
105
  </section>
 
184
  </section>
185
  </article>
186
 
187
+ {% include "../components/dialog-nap-sort.html" with form=form %}
188
 
189
  {% include "../components/toast-container.html" %}
190
  </article>