wagtail-enap-designsystem 1.2.1.121__py3-none-any.whl → 1.2.1.123__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wagtail-enap-designsystem might be problematic. Click here for more details.

Files changed (26) hide show
  1. enap_designsystem/blocks/__init__.py +4 -0
  2. enap_designsystem/blocks/form.py +101 -6
  3. enap_designsystem/blocks/html_blocks.py +199 -52
  4. enap_designsystem/blocks/semana_inovacao.py +7 -1
  5. enap_designsystem/middleware/aluno_sso.py +16 -0
  6. enap_designsystem/migrations/0382_alter_areaaluno_body_alter_cursoeadpage_curso_and_more.py +51080 -0
  7. enap_designsystem/migrations/0383_alter_areaaluno_body_alter_enapcomponentes_body_and_more.py +50922 -0
  8. enap_designsystem/migrations/0384_alter_areaaluno_body_alter_enapcomponentes_body_and_more.py +51606 -0
  9. enap_designsystem/migrations/0385_alter_areaaluno_body_alter_enapcomponentes_body_and_more.py +51947 -0
  10. enap_designsystem/migrations/0386_alter_areaaluno_body_alter_enapcomponentes_body_and_more.py +51809 -0
  11. enap_designsystem/models.py +0 -27
  12. enap_designsystem/templates/custom_404.html +1 -1
  13. enap_designsystem/templates/enap_designsystem/blocks/apresentacao_block.html +116 -0
  14. enap_designsystem/templates/enap_designsystem/blocks/apresentacao_simple_block.html +236 -0
  15. enap_designsystem/templates/enap_designsystem/form_templates/formulario_page.html +490 -13
  16. enap_designsystem/templates/enap_designsystem/includes/form_field.html +661 -4
  17. enap_designsystem/templates/enap_designsystem/pages/mba_especializacao.html +10 -0
  18. enap_designsystem/templates/enap_designsystem/sistema_votacao_page.html +194 -202
  19. enap_designsystem/urls.py +6 -3
  20. enap_designsystem/views.py +118 -153
  21. enap_designsystem/wagtail_hooks.py +235 -77
  22. {wagtail_enap_designsystem-1.2.1.121.dist-info → wagtail_enap_designsystem-1.2.1.123.dist-info}/METADATA +1 -1
  23. {wagtail_enap_designsystem-1.2.1.121.dist-info → wagtail_enap_designsystem-1.2.1.123.dist-info}/RECORD +26 -18
  24. {wagtail_enap_designsystem-1.2.1.121.dist-info → wagtail_enap_designsystem-1.2.1.123.dist-info}/WHEEL +0 -0
  25. {wagtail_enap_designsystem-1.2.1.121.dist-info → wagtail_enap_designsystem-1.2.1.123.dist-info}/licenses/LICENSE +0 -0
  26. {wagtail_enap_designsystem-1.2.1.121.dist-info → wagtail_enap_designsystem-1.2.1.123.dist-info}/top_level.txt +0 -0
@@ -91,9 +91,8 @@
91
91
  background: var(--votacao-bg-primary);
92
92
  border-radius: 16px;
93
93
  padding: 3rem 2rem;
94
- box-shadow: var(--votacao-shadow-md);
95
- border: 1px solid var(--votacao-border-light);
96
94
  color: white;
95
+ border-radius: 0;
97
96
  }
98
97
 
99
98
  .sistema-votacao-header.has-background {
@@ -108,7 +107,6 @@
108
107
  width: 100%;
109
108
  height: 100%;
110
109
  background: rgba(0, 0, 0, 0.5);
111
- border-radius: 16px;
112
110
  z-index: 1;
113
111
  }
114
112
 
@@ -154,7 +152,7 @@
154
152
  align-items: center;
155
153
  background: var(--votacao-bg-primary);
156
154
  border-radius: 12px;
157
- padding: 1rem 2rem;
155
+ padding: 16px;
158
156
  box-shadow: var(--votacao-shadow-md);
159
157
  border: 1px solid var(--votacao-border-light);
160
158
  z-index: 400;
@@ -174,13 +172,16 @@
174
172
  font-size: 1.25rem;
175
173
  font-weight: 700;
176
174
  margin: 0;
177
- color: var(--votacao-text-primary);
175
+ color: #333840;
176
+ text-align: center;
177
+ margin-bottom: 20px;
178
178
  }
179
179
 
180
180
  .sistema-progresso-status {
181
- color: var(--votacao-text-secondary);
181
+ color: #333840;
182
182
  font-size: 0.875rem;
183
183
  font-weight: 500;
184
+ text-align: center;
184
185
  }
185
186
 
186
187
  .sistema-progresso-bar {
@@ -208,10 +209,7 @@
208
209
 
209
210
  .sistema-tabs-container {
210
211
  margin-bottom: 3rem;
211
- background: #EBEFF5;
212
212
  border-radius: 20px;
213
- box-shadow: var(--votacao-shadow-md);
214
- border: 1px solid #C8D1E0;
215
213
  }
216
214
 
217
215
  .sistema-tabs-nav {
@@ -236,11 +234,13 @@
236
234
  white-space: nowrap;
237
235
  font-weight: 500;
238
236
  font-size: 0.9rem;
237
+ max-width: 350px;
238
+ white-space: normal;
239
239
  }
240
240
 
241
241
  .sistema-tab-button:hover {
242
- color: var(--votacao-primary-teal);
243
- background: var(--votacao-gray-50);
242
+ color: white;
243
+ background: #006969;
244
244
  }
245
245
 
246
246
  .sistema-tab-button.active {
@@ -263,7 +263,7 @@
263
263
  }
264
264
 
265
265
  .sistema-categoria-header {
266
- margin-bottom: 2.5rem;
266
+ margin: 2.5rem 0;
267
267
  text-align: center;
268
268
  }
269
269
 
@@ -281,7 +281,7 @@
281
281
 
282
282
  .sistema-projetos-grid {
283
283
  display: grid;
284
- grid-template-columns: 1fr 1fr;
284
+ grid-template-columns: 1fr 1fr 1fr;
285
285
  gap: 2rem;
286
286
  margin-bottom: 3rem;
287
287
  }
@@ -496,8 +496,8 @@
496
496
  .sistema-btn-finalizar {
497
497
  bottom: 2rem;
498
498
  right: 2rem;
499
- background: var(--votacao-bg-primary);
500
- color: var(--votacao-text-secondary);
499
+ background: #007D7A;
500
+ color: white;
501
501
  border: 1px solid var(--votacao-border-medium);
502
502
  padding: 0.875rem 1.25rem;
503
503
  border-radius: 50px;
@@ -818,6 +818,14 @@
818
818
  font-size: 1rem;
819
819
  }
820
820
 
821
+ .alert-red {
822
+ background-color: #FCF0F1;
823
+ padding: 1rem;
824
+ border-radius: 8px;
825
+ margin-bottom: 1rem;
826
+ text-align: center;
827
+ }
828
+
821
829
  .sistema-btn-encerrar-definitivo:hover {
822
830
  background: var(--votacao-gray-50);
823
831
  border-color: var(--votacao-gray-400);
@@ -940,12 +948,10 @@
940
948
 
941
949
  {% block content %}
942
950
  <div class="sistema-votacao-wrapper">
943
- <div class="sistema-votacao-container">
944
- <!-- Header -->
945
- <div class="sistema-votacao-header{% if page.imagem_fundo %} has-background{% endif %}"
951
+ <div class="sistema-votacao-header{% if page.imagem_fundo %} has-background{% endif %}"
946
952
  {% if page.imagem_fundo %}
947
953
  {% for block in page.imagem_fundo %}
948
- style="background-image: url('{{ block.value.file.url }}');"
954
+ style="background-image: url('{{ block.value.file.url }}'); object-fit: cover; object-position: top;"
949
955
  {% endfor %}
950
956
  {% endif %}>
951
957
  <div class="votacao-content">
@@ -962,13 +968,18 @@
962
968
  {% endif %}
963
969
  </div>
964
970
  </div>
971
+ <div class="sistema-votacao-container">
972
+ <!-- Header -->
973
+
965
974
 
966
975
  <!-- Progresso da Votação -->
967
976
  {% if page.mostrar_progresso and categorias %}
968
977
  <div class="sistema-progresso-section">
969
978
  <div class="sistema-progresso-header">
979
+ <div class="alert-red">
970
980
  <h2 class="sistema-progresso-title">Progresso da Votação</h2>
971
981
  <span class="sistema-progresso-status" id="progresso-status">0 de {{ total_categorias }} categorias</span>
982
+ </div>
972
983
  </div>
973
984
 
974
985
  <!-- Botão Finalizar Votação -->
@@ -995,6 +1006,7 @@
995
1006
  {% endfor %}
996
1007
  </div>
997
1008
 
1009
+ <div>
998
1010
  <!-- Conteúdo das Tabs -->
999
1011
  {% for categoria in categorias %}
1000
1012
  <div class="sistema-tab-content {% if forloop.first %}active{% endif %}"
@@ -1098,6 +1110,7 @@
1098
1110
  <p>As categorias e projetos ainda não foram configurados.</p>
1099
1111
  </div>
1100
1112
  {% endif %}
1113
+ </div>
1101
1114
  </div>
1102
1115
  </div>
1103
1116
 
@@ -1187,8 +1200,8 @@
1187
1200
  <!-- CSRF Token -->
1188
1201
  <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
1189
1202
 
1203
+
1190
1204
  <script>
1191
- // Sistema de Votação - Versão Corrigida e Otimizada
1192
1205
  const SistemaVotacao = {
1193
1206
  // Estado da aplicação
1194
1207
  votosCategoria: new Set(),
@@ -1198,31 +1211,23 @@ const SistemaVotacao = {
1198
1211
  configuracao: {
1199
1212
  votacaoAtiva: {% if votacao_ativa %}true{% else %}false{% endif %},
1200
1213
  totalCategorias: {{ total_categorias|default:0 }},
1201
- permitirMultiplosVotos: {% if page.permitir_multiplos_votos %}true{% else %}false{% endif %}
1214
+ permitirMultiplosVotos: {% if page.permitir_multiplos_votos %}true{% else %}false{% endif %},
1215
+ // URL corrigida - usar path absoluto
1216
+ urlVotar: '/votar/'
1202
1217
  },
1203
1218
 
1204
1219
  // Inicialização
1205
1220
  init() {
1206
1221
  console.log('🚀 Inicializando Sistema de Votação...');
1207
1222
 
1208
- // Cache dos elementos DOM
1209
1223
  this.cacheElementos();
1210
-
1211
- // Configurar tabs
1212
1224
  this.configurarTabs();
1213
-
1214
- // Configurar categorias
1215
1225
  this.configurarCategorias();
1216
-
1217
- // Configurar eventos dos modais
1218
1226
  this.configurarModais();
1219
-
1220
- // Configurar CSRF
1221
1227
  this.configurarCSRF();
1222
1228
 
1223
- console.log('✅ Sistema inicializado com sucesso');
1229
+ console.log('✅ Sistema inicializado');
1224
1230
  console.log('📊 Configuração:', this.configuracao);
1225
- console.log('🏷️ Categorias encontradas:', this.categoriasOrdem.length);
1226
1231
  },
1227
1232
 
1228
1233
  // Cache de elementos DOM
@@ -1233,7 +1238,6 @@ const SistemaVotacao = {
1233
1238
  progressoFill: document.getElementById('progresso-fill'),
1234
1239
  progressoStatus: document.getElementById('progresso-status'),
1235
1240
  progressoText: document.querySelector('.sistema-progresso-text'),
1236
- // Elementos do progresso no modal
1237
1241
  progressoFillModal: document.getElementById('progresso-fill-modal'),
1238
1242
  progressoStatusModal: document.getElementById('progresso-status-modal'),
1239
1243
  progressoTextModal: document.getElementById('progresso-text-modal'),
@@ -1242,19 +1246,16 @@ const SistemaVotacao = {
1242
1246
  previewProxima: document.getElementById('preview-proxima-categoria'),
1243
1247
  feedbackMessage: document.getElementById('feedback-message')
1244
1248
  };
1249
+
1250
+ console.log('DOM Elements cached:', Object.keys(this.elementos).length);
1245
1251
  },
1246
1252
 
1247
1253
  // Configurar sistema de tabs
1248
1254
  configurarTabs() {
1249
- console.log('🎯 Configurando tabs...');
1250
-
1251
1255
  this.elementos.tabButtons.forEach((button, index) => {
1252
1256
  const targetId = button.getAttribute('data-tab-target');
1253
1257
  const categoriaId = button.getAttribute('data-categoria-id');
1254
1258
 
1255
- console.log(`Tab ${index}: ${targetId} (categoria: ${categoriaId})`);
1256
-
1257
- // Adicionar event listener
1258
1259
  button.addEventListener('click', (e) => {
1259
1260
  e.preventDefault();
1260
1261
  this.trocarTab(targetId, button);
@@ -1264,8 +1265,6 @@ const SistemaVotacao = {
1264
1265
 
1265
1266
  // Trocar tab ativa
1266
1267
  trocarTab(targetId, clickedButton) {
1267
- console.log('🔄 Trocando tab para:', targetId);
1268
-
1269
1268
  const targetContent = document.getElementById(targetId);
1270
1269
 
1271
1270
  if (!targetContent) {
@@ -1302,13 +1301,10 @@ const SistemaVotacao = {
1302
1301
  icone: iconElement ? iconElement.className : 'fas fa-folder'
1303
1302
  });
1304
1303
  });
1305
-
1306
- console.log('🏷️ Categorias configuradas:', this.categoriasOrdem);
1307
1304
  },
1308
1305
 
1309
1306
  // Configurar modais
1310
1307
  configurarModais() {
1311
- // Fechar modal ao clicar fora
1312
1308
  if (this.elementos.modalPosVoto) {
1313
1309
  this.elementos.modalPosVoto.addEventListener('click', (e) => {
1314
1310
  if (e.target === this.elementos.modalPosVoto) {
@@ -1330,93 +1326,153 @@ const SistemaVotacao = {
1330
1326
  configurarCSRF() {
1331
1327
  const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]');
1332
1328
  if (!csrfToken) {
1333
- console.warn('⚠️ CSRF token não encontrado, criando...');
1334
- const token = document.createElement('input');
1335
- token.type = 'hidden';
1336
- token.name = 'csrfmiddlewaretoken';
1337
- token.value = '{{ csrf_token }}';
1338
- document.body.appendChild(token);
1329
+ console.warn('⚠️ CSRF token não encontrado');
1339
1330
  }
1340
1331
  },
1341
1332
 
1342
- // Função principal de votação
1333
+ // FUNÇÃO PRINCIPAL DE VOTAÇÃO - CORRIGIDA
1343
1334
  async votar(projetoId, categoriaId, button) {
1344
- console.log('🗳️ Votando...', { projetoId, categoriaId });
1335
+ console.log('🗳️ Iniciando votação...', { projetoId, categoriaId });
1345
1336
 
1346
1337
  if (!this.configuracao.votacaoAtiva) {
1347
1338
  this.showFeedback('Votação não está ativa no momento.', 'error');
1348
1339
  return;
1349
1340
  }
1350
1341
 
1342
+ // Verificar se botão já foi usado
1343
+ if (button.classList.contains('votado') || button.disabled) {
1344
+ this.showFeedback('Você já votou neste projeto.', 'warning');
1345
+ return;
1346
+ }
1347
+
1351
1348
  // Estado de loading
1352
1349
  this.setLoadingState(button, true);
1353
1350
 
1354
1351
  try {
1355
- const response = await fetch('{% url "votar_projeto" %}', {
1352
+ // Preparar dados
1353
+ const dados = {
1354
+ projeto_id: parseInt(projetoId),
1355
+ categoria_id: parseInt(categoriaId)
1356
+ };
1357
+
1358
+ console.log('📤 Enviando dados:', dados);
1359
+
1360
+ // Headers da requisição
1361
+ const headers = {
1362
+ 'Content-Type': 'application/json',
1363
+ };
1364
+
1365
+ // Adicionar CSRF token se disponível
1366
+ const csrfToken = this.getCsrfToken();
1367
+ if (csrfToken) {
1368
+ headers['X-CSRFToken'] = csrfToken;
1369
+ }
1370
+
1371
+ // Fazer requisição
1372
+ const response = await fetch(this.configuracao.urlVotar, {
1356
1373
  method: 'POST',
1357
- headers: {
1358
- 'Content-Type': 'application/json',
1359
- 'X-CSRFToken': this.getCsrfToken()
1360
- },
1361
- body: JSON.stringify({
1362
- projeto_id: projetoId,
1363
- categoria_id: categoriaId
1364
- })
1374
+ headers: headers,
1375
+ body: JSON.stringify(dados),
1376
+ credentials: 'same-origin'
1365
1377
  });
1366
1378
 
1367
- const data = await response.json();
1379
+ console.log('📥 Response status:', response.status);
1380
+
1381
+ // Verificar se response é válido
1382
+ if (!response.ok) {
1383
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
1384
+ }
1385
+
1386
+ // Parse do JSON
1387
+ let data;
1388
+ try {
1389
+ data = await response.json();
1390
+ console.log('📊 Response data:', data);
1391
+ } catch (parseError) {
1392
+ console.error('❌ Erro ao fazer parse do JSON:', parseError);
1393
+ throw new Error('Resposta inválida do servidor');
1394
+ }
1368
1395
 
1369
1396
  if (data.success) {
1370
1397
  this.processarVotoSucesso(projetoId, categoriaId, button, data);
1371
1398
  } else {
1372
- throw new Error(data.message || 'Erro ao registrar voto');
1399
+ throw new Error(data.message || 'Erro desconhecido ao registrar voto');
1373
1400
  }
1374
1401
 
1375
1402
  } catch (error) {
1376
- console.error('❌ Erro ao votar:', error);
1377
- this.showFeedback(error.message || 'Erro ao registrar voto. Tente novamente.', 'error');
1403
+ console.error('❌ Erro completo:', error);
1404
+ this.showFeedback(`Erro: ${error.message}`, 'error');
1378
1405
  this.setLoadingState(button, false);
1379
1406
  }
1380
1407
  },
1381
1408
 
1382
1409
  // Processar voto bem-sucedido
1383
1410
  processarVotoSucesso(projetoId, categoriaId, button, data) {
1384
- console.log('✅ Voto registrado com sucesso');
1385
-
1386
- // Atualizar contador se existir
1387
- const contador = document.getElementById(`votos-${projetoId}`);
1388
- if (contador) {
1389
- contador.textContent = data.total_votos || 0;
1390
- }
1411
+ console.log('✅ Voto processado com sucesso:', data);
1391
1412
 
1392
- // Marcar como votado
1413
+ // Atualizar visual do botão
1393
1414
  button.classList.add('votado');
1394
- button.textContent = 'Obrigado pelo seu voto!';
1415
+ button.innerHTML = `
1416
+ <i class="fas fa-check-circle"></i>
1417
+ Voto registrado!
1418
+ `;
1419
+ button.disabled = true;
1395
1420
 
1396
- // Adicionar categoria aos votados
1397
- this.votosCategoria.add(categoriaId);
1421
+ // Atualizar contador se existir
1422
+ this.atualizarContador(projetoId, data.total_votos);
1423
+
1424
+ // Marcar categoria como votada
1425
+ this.votosCategoria.add(parseInt(categoriaId));
1398
1426
  this.atualizarProgresso();
1399
1427
 
1400
- // Desabilitar outros botões se necessário
1428
+ // Desabilitar outros botões da categoria se necessário
1401
1429
  if (!this.configuracao.permitirMultiplosVotos) {
1402
1430
  this.desabilitarOutrosBotoes(categoriaId, button);
1403
1431
  }
1404
1432
 
1433
+ // Mostrar feedback
1434
+ this.showFeedback(`Voto registrado em "${data.projeto_titulo || 'projeto'}"!`, 'success');
1435
+
1405
1436
  // Mostrar próximo passo após delay
1406
1437
  setTimeout(() => {
1407
1438
  this.mostrarModalPosVoto(categoriaId);
1408
- }, 1500);
1439
+ }, 2000);
1440
+ },
1441
+
1442
+ // Atualizar contador de votos
1443
+ atualizarContador(projetoId, totalVotos) {
1444
+ const contadorElement = document.getElementById(`votos-${projetoId}`);
1445
+ if (contadorElement) {
1446
+ const novoTotal = totalVotos || 1;
1447
+ contadorElement.textContent = novoTotal;
1448
+
1449
+ // Animação
1450
+ contadorElement.style.transform = 'scale(1.2)';
1451
+ contadorElement.style.color = '#28a745';
1452
+
1453
+ setTimeout(() => {
1454
+ contadorElement.style.transform = 'scale(1)';
1455
+ contadorElement.style.color = '';
1456
+ }, 500);
1457
+ }
1409
1458
  },
1410
1459
 
1411
1460
  // Desabilitar outros botões da categoria
1412
1461
  desabilitarOutrosBotoes(categoriaId, buttonAtivo) {
1413
- const categoryButtons = document.querySelectorAll(`[data-categoria-id="${categoriaId}"] .sistema-btn-votar`);
1414
- categoryButtons.forEach(btn => {
1415
- if (btn !== buttonAtivo) {
1416
- btn.disabled = true;
1417
- btn.textContent = 'Você votou nesta categoria';
1418
- }
1419
- });
1462
+ const categorySection = document.getElementById(`categoria-${categoriaId}`);
1463
+ if (categorySection) {
1464
+ const outrosBotoes = categorySection.querySelectorAll('.sistema-btn-votar');
1465
+ outrosBotoes.forEach(btn => {
1466
+ if (btn !== buttonAtivo && !btn.classList.contains('votado')) {
1467
+ btn.disabled = true;
1468
+ btn.classList.add('disabled');
1469
+ btn.innerHTML = `
1470
+ <i class="fas fa-ban"></i>
1471
+ Você já votou nesta categoria
1472
+ `;
1473
+ }
1474
+ });
1475
+ }
1420
1476
  },
1421
1477
 
1422
1478
  // Estado de loading do botão
@@ -1424,11 +1480,14 @@ const SistemaVotacao = {
1424
1480
  if (loading) {
1425
1481
  button.classList.add('loading');
1426
1482
  button.disabled = true;
1427
- button.textContent = 'Votando...';
1428
- } else {
1483
+ button.innerHTML = `
1484
+ <i class="fas fa-spinner fa-spin"></i>
1485
+ Votando...
1486
+ `;
1487
+ } else if (!button.classList.contains('votado')) {
1429
1488
  button.classList.remove('loading');
1430
1489
  button.disabled = false;
1431
- button.textContent = 'Votar neste Projeto';
1490
+ button.innerHTML = 'Votar neste Projeto';
1432
1491
  }
1433
1492
  },
1434
1493
 
@@ -1440,13 +1499,16 @@ const SistemaVotacao = {
1440
1499
  if (proximoIndice < this.categoriasOrdem.length) {
1441
1500
  this.proximaCategoriaData = this.categoriasOrdem[proximoIndice];
1442
1501
  this.gerarPreviewProximaCategoria(this.proximaCategoriaData.id);
1443
- this.elementos.modalPosVoto.classList.add('show');
1502
+
1503
+ if (this.elementos.modalPosVoto) {
1504
+ this.elementos.modalPosVoto.classList.add('show');
1505
+ }
1444
1506
  } else {
1445
1507
  this.mostrarModalConclusao();
1446
1508
  }
1447
1509
  },
1448
1510
 
1449
- // Gerar preview da próxima categoria - VERSÃO SEM LIMITE
1511
+ // Gerar preview da próxima categoria
1450
1512
  gerarPreviewProximaCategoria(proximaCategoriaId) {
1451
1513
  const proximaCategoria = document.getElementById(`categoria-${proximaCategoriaId}`);
1452
1514
  const projetos = proximaCategoria ? proximaCategoria.querySelectorAll('.sistema-projeto-card') : [];
@@ -1466,7 +1528,6 @@ const SistemaVotacao = {
1466
1528
  <div class="sistema-preview-projetos">
1467
1529
  `;
1468
1530
 
1469
- // Mostrar TODOS os projetos (sem limite)
1470
1531
  projetos.forEach(projeto => {
1471
1532
  const titulo = projeto.querySelector('.sistema-projeto-title')?.textContent || 'Projeto';
1472
1533
  const equipe = projeto.querySelector('.sistema-equipe-nome')?.textContent || 'Equipe';
@@ -1480,18 +1541,6 @@ const SistemaVotacao = {
1480
1541
  });
1481
1542
 
1482
1543
  previewHTML += `</div>`;
1483
- } else {
1484
- previewHTML = `
1485
- <div class="sistema-preview-header">
1486
- <div class="sistema-preview-icon">
1487
- <i class="fas fa-info-circle"></i>
1488
- </div>
1489
- <h4 class="sistema-preview-title">Próxima categoria disponível</h4>
1490
- </div>
1491
- <p style="text-align: center; color: var(--votacao-text-muted); margin: 1rem 0;">
1492
- Explore mais projetos na próxima categoria!
1493
- </p>
1494
- `;
1495
1544
  }
1496
1545
 
1497
1546
  if (this.elementos.previewProxima) {
@@ -1501,48 +1550,38 @@ const SistemaVotacao = {
1501
1550
 
1502
1551
  // Continuar votação
1503
1552
  continuarVotacao() {
1504
- this.elementos.modalPosVoto.classList.remove('show');
1553
+ if (this.elementos.modalPosVoto) {
1554
+ this.elementos.modalPosVoto.classList.remove('show');
1555
+ }
1505
1556
 
1506
1557
  if (this.proximaCategoriaData) {
1507
1558
  const proximaTab = document.querySelector(`[data-categoria-id="${this.proximaCategoriaData.id}"]`);
1508
1559
  if (proximaTab) {
1509
1560
  proximaTab.click();
1510
-
1511
- setTimeout(() => {
1512
- const categoriaHeader = document.querySelector('.sistema-categoria-header');
1513
- if (categoriaHeader) {
1514
- categoriaHeader.scrollIntoView({
1515
- behavior: 'smooth',
1516
- block: 'start'
1517
- });
1518
- }
1519
- }, 100);
1520
1561
  }
1521
1562
  }
1522
1563
  },
1523
1564
 
1524
1565
  // Parar votação
1525
1566
  pararVotacao() {
1526
- this.elementos.modalPosVoto.classList.remove('show');
1527
- this.showFeedback('Obrigado pela sua participação na votação!', 'success');
1567
+ if (this.elementos.modalPosVoto) {
1568
+ this.elementos.modalPosVoto.classList.remove('show');
1569
+ }
1570
+ this.showFeedback('Obrigado pela sua participação!', 'success');
1528
1571
  },
1529
1572
 
1530
1573
  // Mostrar modal de conclusão
1531
1574
  mostrarModalConclusao() {
1532
- const totalProjetos = document.querySelectorAll('.sistema-projeto-card').length;
1533
- const projetosElement = document.getElementById('total-projetos-visualizados');
1534
- if (projetosElement) {
1535
- projetosElement.textContent = totalProjetos;
1575
+ if (this.elementos.modalConclusao) {
1576
+ this.elementos.modalConclusao.classList.add('show');
1536
1577
  }
1537
-
1538
- this.elementos.modalConclusao.classList.add('show');
1539
1578
  },
1540
1579
 
1541
1580
  // Reiniciar votação
1542
1581
  reiniciarVotacao() {
1543
- console.log('🔄 Reiniciando votação...');
1544
-
1545
- this.elementos.modalConclusao.classList.remove('show');
1582
+ if (this.elementos.modalConclusao) {
1583
+ this.elementos.modalConclusao.classList.remove('show');
1584
+ }
1546
1585
 
1547
1586
  // Reset estado
1548
1587
  this.votosCategoria.clear();
@@ -1551,34 +1590,33 @@ const SistemaVotacao = {
1551
1590
  // Reset botões
1552
1591
  const botoesVotar = document.querySelectorAll('.sistema-btn-votar');
1553
1592
  botoesVotar.forEach(botao => {
1554
- botao.classList.remove('votado', 'loading');
1593
+ botao.classList.remove('votado', 'loading', 'disabled');
1555
1594
  botao.disabled = false;
1556
1595
  botao.textContent = 'Votar neste Projeto';
1557
1596
  });
1558
1597
 
1559
- // Reset progresso
1560
1598
  this.atualizarProgresso();
1561
1599
 
1562
- // Voltar primeira tab
1563
1600
  const primeiraTab = document.querySelector('.sistema-tab-button');
1564
1601
  if (primeiraTab) {
1565
1602
  primeiraTab.click();
1566
1603
  }
1567
1604
 
1568
- window.scrollTo({ top: 0, behavior: 'smooth' });
1569
- this.showFeedback('Nova votação iniciada! Vote novamente.', 'success');
1605
+ this.showFeedback('Nova votação iniciada!', 'success');
1570
1606
  },
1571
1607
 
1572
1608
  // Encerrar definitivo
1573
1609
  encerrarDefinitivo() {
1574
- this.elementos.modalConclusao.classList.remove('show');
1575
- this.showFeedback('Obrigado pela sua participação na votação!', 'success');
1610
+ if (this.elementos.modalConclusao) {
1611
+ this.elementos.modalConclusao.classList.remove('show');
1612
+ }
1613
+ this.showFeedback('Obrigado pela sua participação!', 'success');
1576
1614
  },
1577
1615
 
1578
1616
  // Finalizar votação
1579
1617
  finalizarVotacao() {
1580
1618
  if (this.votosCategoria.size === 0) {
1581
- this.showFeedback('Você ainda não votou em nenhuma categoria.', 'error');
1619
+ this.showFeedback('Você ainda não votou em nenhuma categoria.', 'warning');
1582
1620
  return;
1583
1621
  }
1584
1622
 
@@ -1586,18 +1624,12 @@ const SistemaVotacao = {
1586
1624
 
1587
1625
  let mensagem = 'Tem certeza que deseja finalizar sua votação?';
1588
1626
  if (categoriasRestantes > 0) {
1589
- mensagem += `\n\nAinda há ${categoriasRestantes} categoria${categoriasRestantes > 1 ? 's' : ''} para conhecer.`;
1627
+ mensagem += `\n\nAinda há ${categoriasRestantes} categoria${categoriasRestantes > 1 ? 's' : ''} disponíveis.`;
1590
1628
  }
1591
- mensagem += '\n\nA página será recarregada para iniciar uma nova votação.';
1592
1629
 
1593
1630
  if (confirm(mensagem)) {
1594
- // Mostrar feedback antes de recarregar
1595
- this.showFeedback('Obrigado pela sua participação! Recarregando...', 'success');
1596
-
1597
- // Recarregar a página após um pequeno delay
1598
- setTimeout(() => {
1599
- window.location.reload();
1600
- }, 1500);
1631
+ this.showFeedback('Obrigado pela participação! Recarregando...', 'success');
1632
+ setTimeout(() => window.location.reload(), 1500);
1601
1633
  }
1602
1634
  },
1603
1635
 
@@ -1606,40 +1638,32 @@ const SistemaVotacao = {
1606
1638
  const votadas = this.votosCategoria.size;
1607
1639
  const percentual = Math.round((votadas / this.configuracao.totalCategorias) * 100);
1608
1640
 
1609
- // Atualizar barra principal
1610
- if (this.elementos.progressoFill) {
1611
- this.elementos.progressoFill.style.width = `${percentual}%`;
1612
- }
1613
- if (this.elementos.progressoStatus) {
1614
- this.elementos.progressoStatus.textContent = `${votadas} de ${this.configuracao.totalCategorias} categorias`;
1615
- }
1616
- if (this.elementos.progressoText) {
1617
- this.elementos.progressoText.textContent = `${percentual}% concluído`;
1618
- }
1619
-
1620
- // Atualizar barra do modal
1621
- if (this.elementos.progressoFillModal) {
1622
- this.elementos.progressoFillModal.style.width = `${percentual}%`;
1623
- }
1624
- if (this.elementos.progressoStatusModal) {
1625
- this.elementos.progressoStatusModal.textContent = `${votadas} de ${this.configuracao.totalCategorias} categorias`;
1626
- }
1627
- if (this.elementos.progressoTextModal) {
1628
- this.elementos.progressoTextModal.textContent = `${percentual}% concluído`;
1629
- }
1641
+ // Atualizar elementos de progresso
1642
+ const elementos = [
1643
+ { fill: this.elementos.progressoFill, status: this.elementos.progressoStatus, text: this.elementos.progressoText },
1644
+ { fill: this.elementos.progressoFillModal, status: this.elementos.progressoStatusModal, text: this.elementos.progressoTextModal }
1645
+ ];
1646
+
1647
+ elementos.forEach(({ fill, status, text }) => {
1648
+ if (fill) fill.style.width = `${percentual}%`;
1649
+ if (status) status.textContent = `${votadas} de ${this.configuracao.totalCategorias} categorias`;
1650
+ if (text) text.textContent = `${percentual}% concluído`;
1651
+ });
1630
1652
  },
1631
1653
 
1632
1654
  // Mostrar feedback
1633
1655
  showFeedback(message, type = 'success') {
1634
- if (!this.elementos.feedbackMessage) return;
1656
+ if (!this.elementos.feedbackMessage) {
1657
+ console.log(`Feedback: ${message} (${type})`);
1658
+ return;
1659
+ }
1635
1660
 
1636
1661
  this.elementos.feedbackMessage.textContent = message;
1637
- this.elementos.feedbackMessage.className = `sistema-feedback-message ${type}`;
1638
- this.elementos.feedbackMessage.classList.add('show');
1662
+ this.elementos.feedbackMessage.className = `sistema-feedback-message ${type} show`;
1639
1663
 
1640
1664
  setTimeout(() => {
1641
1665
  this.elementos.feedbackMessage.classList.remove('show');
1642
- }, 3000);
1666
+ }, 4000);
1643
1667
  },
1644
1668
 
1645
1669
  // Obter CSRF token
@@ -1658,50 +1682,18 @@ const SistemaVotacao = {
1658
1682
  }
1659
1683
  }
1660
1684
 
1685
+ console.warn('⚠️ CSRF token não encontrado');
1661
1686
  return '';
1662
- },
1663
-
1664
- // Debug - testar funcionalidades
1665
- debug: {
1666
- testarTab(categoriaId) {
1667
- const button = document.querySelector(`[data-categoria-id="${categoriaId}"]`);
1668
- if (button) {
1669
- console.log('🧪 Testando clique na categoria:', categoriaId);
1670
- button.click();
1671
- } else {
1672
- console.error('❌ Botão não encontrado para categoria:', categoriaId);
1673
- }
1674
- },
1675
-
1676
- infoTabs() {
1677
- console.log('=== DEBUG TABS ===');
1678
- console.log('Botões:', document.querySelectorAll('.sistema-tab-button').length);
1679
- console.log('Conteúdos:', document.querySelectorAll('.sistema-tab-content').length);
1680
-
1681
- document.querySelectorAll('.sistema-tab-button').forEach((btn, i) => {
1682
- console.log(`Botão ${i}:`, {
1683
- target: btn.getAttribute('data-tab-target'),
1684
- categoriaId: btn.getAttribute('data-categoria-id'),
1685
- ativo: btn.classList.contains('active')
1686
- });
1687
- });
1688
- },
1689
-
1690
- infoEstado() {
1691
- console.log('=== ESTADO ATUAL ===');
1692
- console.log('Votos por categoria:', Array.from(SistemaVotacao.votosCategoria));
1693
- console.log('Configuração:', SistemaVotacao.configuracao);
1694
- console.log('Categorias:', SistemaVotacao.categoriasOrdem);
1695
- }
1696
1687
  }
1697
1688
  };
1698
1689
 
1699
- // Inicialização quando DOM carregar
1690
+ // Inicialização
1700
1691
  document.addEventListener('DOMContentLoaded', function() {
1692
+ console.log('📄 DOM carregado, inicializando sistema...');
1701
1693
  SistemaVotacao.init();
1702
1694
  });
1703
1695
 
1704
- // Expor funções globalmente para compatibilidade
1696
+ // Expor globalmente
1705
1697
  window.SistemaVotacao = SistemaVotacao;
1706
1698
  </script>
1707
1699
  {% endblock %}