chartManD commited on
Commit
8d9f6d7
·
1 Parent(s): aa9b96e

Refactorizacion de nappgin con perfil ultra flash

Browse files
tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_napping_controller.py CHANGED
@@ -72,9 +72,9 @@ class InitSessionNappingController(InitSessionController):
72
 
73
  def setStatusSession(self):
74
  technique_mode = TecnicaModalidad.objects.get(
75
- tecnica=self.session.tecnica, usando=True)
76
 
77
- if technique_mode.modalidad.nombre == "sin modalidad":
78
  self.context["status"] = "La sesión usa Napping"
79
  else:
80
- self.context["status"] = f"La sesión usa Napping con modalidad {technique_mode.modalidad.nombre}"
 
72
 
73
  def setStatusSession(self):
74
  technique_mode = TecnicaModalidad.objects.get(
75
+ tecnica=self.session.tecnica).modalidad.nombre
76
 
77
+ if technique_mode == "sin modalidad":
78
  self.context["status"] = "La sesión usa Napping"
79
  else:
80
+ self.context["status"] = f"La sesión usa Napping con modalidad {technique_mode}"
tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_napping_controller.py CHANGED
@@ -28,7 +28,7 @@ class TestNappingController(GenetalTestController):
28
  return redirect(reverse(self.previus_directory, kwargs=params))
29
 
30
  name_mode_activate = TecnicaModalidad.objects.get(
31
- tecnica=technique, usando=True).modalidad.nombre
32
 
33
  if name_mode_activate == "sin modalidad":
34
  self.context["mode"] = "sin modalidad"
@@ -60,9 +60,7 @@ class TestNappingController(GenetalTestController):
60
 
61
  def nappingPufTest(self, request: HttpRequest):
62
  maked_previus_napping = TecnicaModalidad.objects.get(
63
- tecnica=self.session.tecnica,
64
- modalidad=Modalidad.objects.get(nombre="sin modalidad")
65
- )
66
 
67
  self.context["maked_napping"] = True if maked_previus_napping else False
68
  self.context["mode"] = "perfil ultra flash"
@@ -91,7 +89,7 @@ class TestNappingController(GenetalTestController):
91
  code=F("calificacion__id_producto__codigoProducto"),
92
  px=F("x"),
93
  py=F("y"),
94
- id_product=F("calificacion__id_producto")
95
  )
96
 
97
  self.context["data_points"] = list(data_points)
 
28
  return redirect(reverse(self.previus_directory, kwargs=params))
29
 
30
  name_mode_activate = TecnicaModalidad.objects.get(
31
+ tecnica=technique).modalidad.nombre
32
 
33
  if name_mode_activate == "sin modalidad":
34
  self.context["mode"] = "sin modalidad"
 
60
 
61
  def nappingPufTest(self, request: HttpRequest):
62
  maked_previus_napping = TecnicaModalidad.objects.get(
63
+ tecnica=self.session.tecnica)
 
 
64
 
65
  self.context["maked_napping"] = True if maked_previus_napping else False
66
  self.context["mode"] = "perfil ultra flash"
 
89
  code=F("calificacion__id_producto__codigoProducto"),
90
  px=F("x"),
91
  py=F("y"),
92
+ id_product=F("calificacion__id_producto__id")
93
  )
94
 
95
  self.context["data_points"] = list(data_points)
tecnicas/static/js/test-napping-plane.js CHANGED
@@ -13,13 +13,16 @@ let selectedProductId = null;
13
  window.placedPoints = {};
14
 
15
  const modeElement = document.querySelector('[data-mode]');
16
- window.isUltraFlash = modeElement && modeElement.dataset.mode.toLowerCase().includes('ultra flash') || None;
17
 
 
 
18
  if (window.isUltraFlash) {
19
  document.getElementById("question-save").classList.add("hidden");
20
  window.isPlacementActive = true;
21
  } else {
22
- window.isPlacementActive = false;
 
23
  }
24
 
25
  // 1. Handle Product Selection
@@ -90,15 +93,6 @@ window.renderPoint = function (code, xPx, yPx, xVal, yVal) {
90
  point.style.left = `${xPx}px`;
91
  point.style.top = `${yPx}px`;
92
 
93
- const label = document.createElement('div');
94
- label.className = 'absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-2 py-1 bg-gray-800 text-white text-xs rounded whitespace-nowrap z-10 hidden group-hover:block';
95
- label.innerHTML = `
96
- <strong>${code}</strong><br>
97
- X: ${xVal.toFixed(1)}<br>
98
- Y: ${yVal.toFixed(1)}
99
- `;
100
-
101
- point.appendChild(label);
102
  planeContainer.appendChild(point);
103
 
104
  const textLabel = document.createElement('span');
 
13
  window.placedPoints = {};
14
 
15
  const modeElement = document.querySelector('[data-mode]');
16
+ window.isUltraFlash = modeElement && modeElement.dataset.mode.toLowerCase().includes('ultra flash');
17
 
18
+ // For normal mode (sin modalidad), placement is always active
19
+ // For ultra flash mode, it starts active but will be controlled by ultra-flash.js
20
  if (window.isUltraFlash) {
21
  document.getElementById("question-save").classList.add("hidden");
22
  window.isPlacementActive = true;
23
  } else {
24
+ // Normal mode: placement is always active
25
+ window.isPlacementActive = true;
26
  }
27
 
28
  // 1. Handle Product Selection
 
93
  point.style.left = `${xPx}px`;
94
  point.style.top = `${yPx}px`;
95
 
 
 
 
 
 
 
 
 
 
96
  planeContainer.appendChild(point);
97
 
98
  const textLabel = document.createElement('span');
tecnicas/static/js/test-napping-ultra-flash.js CHANGED
@@ -1,5 +1,7 @@
1
  // Store words: { "CODE": ["word1", "word2"] }
2
  const productWords = {};
 
 
3
  if (window.isUltraFlash) {
4
  initUltraFlash(productWords);
5
  }
@@ -20,25 +22,31 @@ function initUltraFlash(productWords) {
20
  const points = document.querySelectorAll('.data-point');
21
  let hasExistingWords = false;
22
 
23
- // Check if there are existing words
24
  points.forEach(point => {
25
  const code = point.dataset.code;
26
  const wordsAttr = point.dataset.words;
27
 
28
- if (wordsAttr) {
29
- productWords[code] = wordsAttr.split(',').filter(w => w);
30
- hasExistingWords = true;
 
 
31
  }
32
  });
33
 
 
34
  if (hasExistingWords) {
35
  startDescriptionPhase();
 
36
  points.forEach(point => {
37
  const code = point.dataset.code;
38
- updatePointLabel(code);
39
- console.log(productWords[code]);
 
40
  });
41
  } else {
 
42
  continueBtn.classList.remove('hidden');
43
  }
44
 
@@ -57,15 +65,24 @@ function initUltraFlash(productWords) {
57
 
58
  function startDescriptionPhase() {
59
  isDescriptionPhase = true;
60
- window.isPlacementActive = false;
 
 
61
  continueBtn.classList.add('hidden');
62
- document.getElementById("question-save").classList.remove("hidden");
63
 
 
64
  spanNotifaction("Fase de descripción: Haz clic en un punto para agregar palabras.", false);
65
 
66
- document.getElementById('napping-plane').classList.remove('cursor-crosshair');
67
- document.getElementById('napping-plane').classList.add('cursor-default');
68
- document.querySelectorAll('.item-product').forEach(p => p.classList.remove('ring-4', 'ring-primary'))
 
 
 
 
 
 
69
  }
70
 
71
  // Handle Point Click for Description
@@ -120,10 +137,7 @@ function initUltraFlash(productWords) {
120
  productWords[currentProductCode] = [];
121
  }
122
 
123
- if (productWords[currentProductCode].length >= 5) {
124
- spanNotifaction("Máximo 5 palabras por producto.");
125
- return;
126
- }
127
 
128
  if (productWords[currentProductCode].includes(word)) {
129
  spanNotifaction("Palabra duplicada");
@@ -155,56 +169,61 @@ function initUltraFlash(productWords) {
155
  const point = document.getElementById(`point-${code}`);
156
  if (!point) return;
157
 
158
- // Find or create the words container below the point
159
- const tooltip = point.querySelector('.group-hover\\:block');
 
 
160
  if (tooltip) {
161
- // Rebuild tooltip content
162
- const xVal = parseFloat(point.dataset.px).toFixed(1);
163
- const yVal = parseFloat(point.dataset.py).toFixed(1);
164
- const words = productWords[code] || [];
165
-
166
- let wordsHtml = '';
167
- if (words.length > 0) {
168
- wordsHtml = `<div class="mt-1 pt-1 border-t border-gray-600 text-yellow-300 italic">${words.join(', ')}</div>`;
169
- }
170
 
 
 
 
 
 
 
 
171
  tooltip.innerHTML = `
172
- <strong>${code}</strong><br>
173
- X: ${xVal}<br>
174
- Y: ${yVal}
175
- ${wordsHtml}
176
  `;
 
 
 
 
 
 
177
  }
178
  }
179
 
180
- // Override saveData to include words
181
- // We need to hook into the existing saveData or replace it.
182
- // Since we made saveData global, we can wrap it.
 
 
183
 
184
- const originalSaveData = window.saveData;
 
 
 
 
185
 
186
- window.saveData = async function () {
187
- // If in description phase, validate words
188
  if (isDescriptionPhase) {
189
- const codes = Object.keys(window.placedPoints);
190
- for (const code of codes) {
191
  const words = productWords[code] || [];
192
- if (words.length < 3) {
193
- spanNotifaction(`El producto ${code} debe tener al menos 3 palabras.`);
194
  return false;
195
  }
196
  }
197
  }
198
 
199
- // Prepare data
200
- const codeProducts = Object.keys(window.placedPoints);
201
  const data = [];
202
-
203
- if (document.querySelectorAll('.item-product').length != codeProducts.length) {
204
- spanNotifaction("Por favor, coloca todos los puntos")
205
- return false;
206
- }
207
-
208
  codeProducts.forEach((code) => {
209
  const point = window.placedPoints[code];
210
  const words = productWords[code] || [];
@@ -214,17 +233,14 @@ function initUltraFlash(productWords) {
214
  x: point.x,
215
  y: point.y,
216
  idProduct: point.id,
217
- words: words // Add words here
218
  };
219
 
220
  data.push(objData);
221
- })
222
-
223
- // We can reuse the rest of the logic, but we need to send the data.
224
- // The original function constructs data inside it. We can't easily inject data into it unless we rewrite it.
225
- // So I will rewrite the fetch part here.
226
 
227
- const URL = "/cata/testers/api/rating-napping/no-mode"
 
228
  const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
229
 
230
  try {
@@ -235,25 +251,25 @@ function initUltraFlash(productWords) {
235
  "X-CSRFToken": csrfToken,
236
  },
237
  body: JSON.stringify(data),
238
- })
239
 
240
  if (!response.ok) {
241
- spanNotifaction("Error en la respuesta del servidor")
242
  return false;
243
  }
244
 
245
- const result = await response.json()
246
 
247
  if (result.error) {
248
- spanNotifaction(result.error)
249
- return false
250
  } else {
251
- spanNotifaction(result.message, false)
252
- return true
253
  }
254
  } catch (error) {
255
- spanNotifaction("Error en proceso de guardar los datos")
256
- return false
257
  }
258
  }
259
  }
 
1
  // Store words: { "CODE": ["word1", "word2"] }
2
  const productWords = {};
3
+
4
+ // Only initialize ultra flash if the mode is active
5
  if (window.isUltraFlash) {
6
  initUltraFlash(productWords);
7
  }
 
22
  const points = document.querySelectorAll('.data-point');
23
  let hasExistingWords = false;
24
 
25
+ // Check if there are existing words from backend
26
  points.forEach(point => {
27
  const code = point.dataset.code;
28
  const wordsAttr = point.dataset.words;
29
 
30
+ if (wordsAttr && wordsAttr.trim() !== '') {
31
+ productWords[code] = wordsAttr.split(',').filter(w => w.trim() !== '');
32
+ if (productWords[code].length > 0) {
33
+ hasExistingWords = true;
34
+ }
35
  }
36
  });
37
 
38
+ // If words already exist, skip phase 1 and go directly to description phase
39
  if (hasExistingWords) {
40
  startDescriptionPhase();
41
+ // Update all point labels to show existing words
42
  points.forEach(point => {
43
  const code = point.dataset.code;
44
+ if (productWords[code] && productWords[code].length > 0) {
45
+ updatePointLabel(code);
46
+ }
47
  });
48
  } else {
49
+ // No existing words, show continue button for phase 1
50
  continueBtn.classList.remove('hidden');
51
  }
52
 
 
65
 
66
  function startDescriptionPhase() {
67
  isDescriptionPhase = true;
68
+ window.isPlacementActive = false; // Freeze point placement
69
+
70
+ // Hide continue button and show finish options
71
  continueBtn.classList.add('hidden');
72
+ questionSaveBtn.classList.remove("hidden");
73
 
74
+ // Update UI to indicate description phase
75
  spanNotifaction("Fase de descripción: Haz clic en un punto para agregar palabras.", false);
76
 
77
+ // Change cursor style to indicate different mode
78
+ const plane = document.getElementById('napping-plane');
79
+ plane.classList.remove('cursor-crosshair');
80
+ plane.classList.add('cursor-default');
81
+
82
+ // Remove any product selection highlights
83
+ document.querySelectorAll('.item-product').forEach(p => {
84
+ p.classList.remove('ring-4', 'ring-primary');
85
+ });
86
  }
87
 
88
  // Handle Point Click for Description
 
137
  productWords[currentProductCode] = [];
138
  }
139
 
140
+ // No maximum limit on words
 
 
 
141
 
142
  if (productWords[currentProductCode].includes(word)) {
143
  spanNotifaction("Palabra duplicada");
 
169
  const point = document.getElementById(`point-${code}`);
170
  if (!point) return;
171
 
172
+ const words = productWords[code] || [];
173
+
174
+ // Remove existing tooltip if present
175
+ let tooltip = point.querySelector('.group-hover\\:block');
176
  if (tooltip) {
177
+ tooltip.remove();
178
+ }
 
 
 
 
 
 
 
179
 
180
+ // Only create tooltip in description phase and if there are words
181
+ if (isDescriptionPhase && words.length > 0) {
182
+ tooltip = document.createElement('div');
183
+ tooltip.className = 'absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-3 py-2 bg-gray-800 text-white text-xs rounded z-10 hidden group-hover:block';
184
+
185
+ // Display words in a 3-column grid (no coordinates)
186
+ const wordBadges = words.map(w => `<span class="inline-block px-2 py-1 bg-yellow-600 text-white rounded text-xs">${w}</span>`).join('');
187
  tooltip.innerHTML = `
188
+ <strong>${code}</strong>
189
+ <div class="mt-2 pt-2 border-t border-gray-600" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; max-width: 300px;">
190
+ ${wordBadges}
191
+ </div>
192
  `;
193
+
194
+ // Add max-width to tooltip
195
+ tooltip.style.maxWidth = '320px';
196
+ tooltip.style.whiteSpace = 'normal';
197
+
198
+ point.appendChild(tooltip);
199
  }
200
  }
201
 
202
+ // Override saveData to include words for ultra flash mode
203
+ // This replaces the basic saveData from test-napping-plane.js
204
+ window.saveData = async function () {
205
+ const codeProducts = Object.keys(window.placedPoints);
206
+ const totalProducts = document.querySelectorAll('.item-product').length;
207
 
208
+ // Validate all products are placed
209
+ if (totalProducts != codeProducts.length) {
210
+ spanNotifaction("Por favor, coloca todos los puntos");
211
+ return false;
212
+ }
213
 
214
+ // If in description phase, validate words (minimum 1 per product)
 
215
  if (isDescriptionPhase) {
216
+ for (const code of codeProducts) {
 
217
  const words = productWords[code] || [];
218
+ if (words.length < 1) {
219
+ spanNotifaction(`El producto ${code} debe tener al menos 1 palabra.`);
220
  return false;
221
  }
222
  }
223
  }
224
 
225
+ // Prepare data with coordinates and words
 
226
  const data = [];
 
 
 
 
 
 
227
  codeProducts.forEach((code) => {
228
  const point = window.placedPoints[code];
229
  const words = productWords[code] || [];
 
233
  x: point.x,
234
  y: point.y,
235
  idProduct: point.id,
236
+ words: words // Include words for ultra flash mode
237
  };
238
 
239
  data.push(objData);
240
+ });
 
 
 
 
241
 
242
+ // Send data to server
243
+ const URL = "/cata/testers/api/rating-napping/no-mode";
244
  const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
245
 
246
  try {
 
251
  "X-CSRFToken": csrfToken,
252
  },
253
  body: JSON.stringify(data),
254
+ });
255
 
256
  if (!response.ok) {
257
+ spanNotifaction("Error en la respuesta del servidor");
258
  return false;
259
  }
260
 
261
+ const result = await response.json();
262
 
263
  if (result.error) {
264
+ spanNotifaction(result.error);
265
+ return false;
266
  } else {
267
+ spanNotifaction(result.message, false);
268
+ return true;
269
  }
270
  } catch (error) {
271
+ spanNotifaction("Error en proceso de guardar los datos");
272
+ return false;
273
  }
274
  }
275
  }