@kaikybrofc/omnizap-system 2.3.1 → 2.3.3

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.
Files changed (49) hide show
  1. package/README.md +82 -483
  2. package/app/controllers/messageController.js +473 -255
  3. package/app/modules/analyticsModule/messageAnalysisEventRepository.js +83 -0
  4. package/app/modules/stickerModule/stickerCommand.js +7 -2
  5. package/app/modules/stickerModule/stickerTextCommand.js +7 -2
  6. package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +1 -3
  7. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +224 -53
  8. package/app/observability/metrics.js +6 -3
  9. package/app/services/googleWebLinkService.js +77 -0
  10. package/app/services/lidMapService.js +83 -4
  11. package/database/index.js +2 -0
  12. package/database/migrations/20260301_0028_message_analysis_event.sql +32 -0
  13. package/database/migrations/20260301_0029_admin_action_audit.sql +16 -0
  14. package/package.json +1 -1
  15. package/public/index.html +12 -8
  16. package/public/js/apps/createPackApp.js +4 -4
  17. package/public/js/apps/homeApp.js +78 -34
  18. package/public/js/apps/loginApp.js +245 -35
  19. package/public/js/apps/stickersAdminApp.js +4 -10
  20. package/public/js/apps/stickersApp.js +1 -1
  21. package/public/js/apps/userApp.js +956 -55
  22. package/public/js/apps/userProfileApp.js +244 -0
  23. package/public/login/index.html +437 -101
  24. package/public/termos-de-uso/index.html +1 -1
  25. package/public/user/index.html +2 -181
  26. package/public/user/systemadm/index.html +774 -0
  27. package/server/controllers/stickerCatalog/nonCatalogHandlers.js +183 -0
  28. package/server/controllers/stickerCatalogController.js +1289 -368
  29. package/server/controllers/systemAdminController.js +141 -0
  30. package/server/controllers/userController.js +87 -0
  31. package/server/http/httpServer.js +72 -32
  32. package/server/middleware/cachePolicy.js +24 -0
  33. package/server/middleware/cachePolicyHelpers.js +1 -0
  34. package/server/middleware/rateLimit.js +89 -0
  35. package/server/middleware/requestLogger.js +16 -0
  36. package/server/middleware/requireAdminAuth.js +42 -0
  37. package/server/middleware/securityHeaders.js +6 -0
  38. package/server/routes/admin/systemAdminRouter.js +56 -0
  39. package/server/routes/health/healthRouter.js +41 -0
  40. package/server/routes/indexRouter.js +197 -0
  41. package/server/routes/metrics/metricsRouter.js +13 -0
  42. package/server/routes/stickerCatalog/catalogHandlers/catalogAdminHttp.js +44 -0
  43. package/server/routes/stickerCatalog/stickerApiRouter.js +84 -0
  44. package/server/routes/stickerCatalog/stickerDataRouter.js +140 -0
  45. package/server/routes/stickerCatalog/stickerSiteRouter.js +43 -0
  46. package/server/routes/user/userRouter.js +56 -0
  47. package/server/utils/safePath.js +26 -0
  48. package/server/routes/metricsRoute.js +0 -7
  49. package/server/routes/stickerCatalogRoute.js +0 -20
@@ -25,21 +25,25 @@
25
25
  </script>
26
26
  <style>
27
27
  :root {
28
- --bg: #0f172a;
29
- --bg-2: #111827;
30
- --card: #1e293bcf;
31
- --line: rgba(255, 255, 255, 0.05);
28
+ --bg: #070f20;
29
+ --bg-2: #0b1730;
30
+ --card: #10213dcc;
31
+ --line: rgba(148, 163, 184, 0.28);
32
32
  --text: #f8fafc;
33
- --muted: #94a3b8;
33
+ --muted: #9eb1cf;
34
34
  --primary: #22c55e;
35
35
  --error: #f87171;
36
- --radius: 18px;
36
+ --radius: 20px;
37
37
  }
38
38
 
39
39
  * {
40
40
  box-sizing: border-box;
41
41
  }
42
42
 
43
+ [hidden] {
44
+ display: none !important;
45
+ }
46
+
43
47
  html,
44
48
  body {
45
49
  margin: 0;
@@ -50,28 +54,28 @@
50
54
  body {
51
55
  color: var(--text);
52
56
  font-family: 'Manrope', system-ui, sans-serif;
53
- background: radial-gradient(55rem 22rem at -10% -10%, #2563eb30, transparent 60%), radial-gradient(55rem 22rem at 110% -8%, #7c3aed22, transparent 56%), linear-gradient(160deg, var(--bg), var(--bg-2));
57
+ background: radial-gradient(56rem 25rem at -8% -16%, #2563eb2f, transparent 62%), radial-gradient(54rem 22rem at 108% -8%, #22c55e1f, transparent 60%), linear-gradient(165deg, var(--bg), var(--bg-2));
54
58
  min-height: 100vh;
55
59
  display: flex;
56
60
  align-items: center;
57
61
  justify-content: center;
58
- padding: 24px 14px;
62
+ padding: 28px 14px;
59
63
  }
60
64
 
61
65
  .page {
62
- width: min(760px, 100%);
63
- border: 1px solid rgba(255, 255, 255, 0.05);
64
- border-radius: 24px;
65
- background: linear-gradient(150deg, #111827e8, #1e293bee);
66
+ width: min(780px, 100%);
67
+ border: 1px solid rgba(148, 163, 184, 0.18);
68
+ border-radius: 26px;
69
+ background: linear-gradient(150deg, #0a1429f0, #0f1f3ce8);
66
70
  box-shadow:
67
- 0 18px 44px #0209166e,
68
- inset 0 1px 0 #95c1ff1a;
71
+ 0 24px 52px #02091682,
72
+ inset 0 1px 0 #95c1ff1c;
69
73
  overflow: hidden;
70
74
  }
71
75
 
72
76
  .head {
73
- border-bottom: 1px solid rgba(255, 255, 255, 0.05);
74
- padding: 20px 22px;
77
+ border-bottom: 1px solid rgba(148, 163, 184, 0.16);
78
+ padding: 18px 24px;
75
79
  display: flex;
76
80
  align-items: center;
77
81
  justify-content: flex-start;
@@ -94,56 +98,79 @@
94
98
  width: 30px;
95
99
  height: 30px;
96
100
  border-radius: 50%;
97
- border: 1px solid rgba(255, 255, 255, 0.05);
101
+ border: 1px solid rgba(148, 163, 184, 0.24);
98
102
  object-fit: cover;
99
103
  }
100
104
 
101
105
  .btn {
102
- border: 1px solid var(--line);
103
- border-radius: 12px;
104
- background: #101a2f;
105
- color: var(--text);
106
+ border: 1px solid #385180;
107
+ border-radius: 13px;
108
+ background: #122446;
109
+ color: #d6e8ff;
106
110
  text-decoration: none;
107
- padding: 9px 12px;
111
+ padding: 11px 14px;
108
112
  font-size: 14px;
109
- font-weight: 600;
113
+ font-weight: 700;
114
+ text-align: center;
110
115
  transition:
111
116
  transform 0.2s ease,
112
117
  border-color 0.2s ease,
113
- box-shadow 0.2s ease;
118
+ box-shadow 0.2s ease,
119
+ background-color 0.2s ease;
114
120
  cursor: pointer;
115
121
  }
116
122
 
117
123
  .btn:hover {
118
- transform: translateY(-1px);
119
- border-color: #2563eb;
120
- box-shadow: 0 10px 20px #02091650;
124
+ transform: translateY(-2px);
125
+ border-color: #60a5fa;
126
+ box-shadow: 0 14px 28px #02091666;
121
127
  }
122
128
 
123
129
  .btn.primary {
124
- border-color: transparent;
125
- background: #22c55e;
126
- color: #0f172a;
127
- box-shadow: 0 10px 22px #22c55e30;
130
+ border-color: #2fdc74;
131
+ background: linear-gradient(98deg, #22c55e, #1ea853);
132
+ color: #0a1a11;
133
+ box-shadow:
134
+ 0 0 0 1px #6ee7b733 inset,
135
+ 0 14px 26px #22c55e42,
136
+ 0 0 22px #2563eb2f;
128
137
  }
129
138
 
130
139
  .btn.primary:hover {
131
- background: #16a34a;
140
+ background: linear-gradient(98deg, #2ad668, #1fa857);
141
+ box-shadow:
142
+ 0 0 0 1px #86efac44 inset,
143
+ 0 18px 30px #22c55e4f,
144
+ 0 0 24px #2563eb40;
132
145
  }
133
146
 
134
147
  .content {
135
- padding: 24px 22px;
148
+ padding: 30px 24px 26px;
136
149
  display: grid;
137
- gap: 14px;
150
+ gap: 16px;
151
+ }
152
+
153
+ .eyebrow {
154
+ margin: 0;
155
+ width: fit-content;
156
+ border: 1px solid #315486;
157
+ border-radius: 999px;
158
+ padding: 6px 11px;
159
+ background: #10264a;
160
+ color: #c0d9ff;
161
+ font-size: 12px;
162
+ font-weight: 700;
163
+ letter-spacing: 0.04em;
164
+ text-transform: uppercase;
138
165
  }
139
166
 
140
167
  h1 {
141
168
  margin: 0;
142
169
  font-family: 'Sora', sans-serif;
143
- font-size: clamp(26px, 3.6vw, 36px);
144
- line-height: 1.08;
170
+ font-size: clamp(30px, 4vw, 40px);
171
+ line-height: 1.04;
145
172
  letter-spacing: -0.02em;
146
- background: linear-gradient(90deg, #eef5ff 0%, #60a5fa 46%, #a78bfa 100%);
173
+ background: linear-gradient(90deg, #f5f9ff 0%, #9cc8ff 46%, #bbd8ff 100%);
147
174
  -webkit-background-clip: text;
148
175
  background-clip: text;
149
176
  color: transparent;
@@ -151,26 +178,47 @@
151
178
 
152
179
  .lead {
153
180
  margin: 0;
154
- color: #bfd1ea;
155
- line-height: 1.6;
156
- font-size: 16px;
181
+ color: #c8d9f4;
182
+ line-height: 1.55;
183
+ font-size: 17px;
157
184
  }
158
185
 
159
186
  .card {
160
- border: 1px solid #334f7bc7;
187
+ border: 1px solid #365584c4;
161
188
  border-radius: var(--radius);
162
- background: var(--card);
163
- padding: 16px;
189
+ background: linear-gradient(150deg, var(--card), #0d1c37d9);
190
+ padding: 20px;
164
191
  display: grid;
165
- gap: 10px;
166
- backdrop-filter: blur(8px);
192
+ gap: 12px;
193
+ backdrop-filter: blur(12px);
194
+ box-shadow:
195
+ 0 16px 32px #02091652,
196
+ inset 0 1px 0 #9cc8ff1c;
167
197
  }
168
198
 
169
199
  .status {
170
200
  margin: 0;
171
- color: #dce8fa;
172
- font-size: 15px;
201
+ width: fit-content;
202
+ border: 1px solid #4170aa;
203
+ border-radius: 999px;
204
+ background: #0f274b;
205
+ color: #e6f1ff;
206
+ padding: 8px 12px;
207
+ font-size: 14px;
208
+ font-weight: 700;
173
209
  line-height: 1.5;
210
+ display: inline-flex;
211
+ align-items: center;
212
+ gap: 8px;
213
+ }
214
+
215
+ .status::before {
216
+ content: '';
217
+ width: 8px;
218
+ height: 8px;
219
+ border-radius: 50%;
220
+ background: #60a5fa;
221
+ box-shadow: 0 0 0 4px #60a5fa24;
174
222
  }
175
223
 
176
224
  .hint {
@@ -182,57 +230,196 @@
182
230
 
183
231
  .error {
184
232
  margin: 0;
185
- border: 1px solid #a74949;
233
+ border: 1px solid #b15050;
186
234
  border-radius: 12px;
187
- background: #3b181899;
235
+ background: #411b1b9e;
188
236
  color: #ffd7d7;
189
- padding: 9px 10px;
237
+ padding: 10px 12px;
238
+ font-size: 14px;
239
+ }
240
+
241
+ .already-logged {
242
+ border: 1px solid #2f9461bf;
243
+ border-radius: 14px;
244
+ background: linear-gradient(150deg, #0f2f21cc, #103126d9);
245
+ padding: 14px;
246
+ display: grid;
247
+ gap: 6px;
248
+ box-shadow:
249
+ 0 14px 26px #22c55e1e,
250
+ inset 0 1px 0 #7af3ab33;
251
+ }
252
+
253
+ .already-logged-title {
254
+ margin: 0;
255
+ font-family: 'Sora', sans-serif;
256
+ font-size: clamp(20px, 2.4vw, 24px);
257
+ line-height: 1.15;
258
+ color: #e7fff1;
259
+ letter-spacing: -0.01em;
260
+ }
261
+
262
+ .already-logged-detail {
263
+ margin: 0;
264
+ color: #c5f5d9;
190
265
  font-size: 14px;
266
+ line-height: 1.5;
191
267
  }
192
268
 
193
269
  .google-area {
194
- border: 1px dashed #3c5b8d;
270
+ border: 1px dashed #456da4;
195
271
  border-radius: 14px;
196
- background: #111827a3;
197
- padding: 12px;
272
+ background: #0d1b34cc;
273
+ padding: 14px;
198
274
  display: grid;
199
- gap: 10px;
275
+ gap: 12px;
200
276
  align-items: stretch;
201
277
  }
202
278
 
203
- html:not([data-login-has-wa='1']) #google-login-area {
204
- display: none !important;
279
+ .google-button-shell {
280
+ border: 1px solid #bfd5ff6b;
281
+ border-radius: 14px;
282
+ background: #ffffff;
283
+ padding: 8px;
284
+ overflow: hidden;
285
+ box-shadow:
286
+ 0 8px 18px #02091624,
287
+ inset 0 1px 0 #ffffff;
288
+ transition:
289
+ transform 0.2s ease,
290
+ box-shadow 0.2s ease;
291
+ }
292
+
293
+ .google-button-shell:hover {
294
+ transform: translateY(-1px);
295
+ box-shadow:
296
+ 0 12px 22px #0209163b,
297
+ inset 0 1px 0 #ffffff;
205
298
  }
206
299
 
207
300
  [data-google-login-button] {
208
301
  width: 100%;
209
- min-height: 40px;
302
+ max-width: 100%;
303
+ min-height: 44px;
304
+ overflow: hidden;
305
+ }
306
+
307
+ [data-google-login-button] > div,
308
+ [data-google-login-button] iframe {
309
+ max-width: 100% !important;
210
310
  }
211
311
 
212
312
  .google-state {
213
313
  margin: 0;
214
- color: var(--muted);
215
- font-size: 13px;
314
+ color: #9db6d9;
315
+ font-size: 12px;
216
316
  }
217
317
 
218
- .summary {
219
- border: 1px solid #2b8b5d9c;
318
+ .consent {
319
+ border: 1px solid #3d5b87;
220
320
  border-radius: 12px;
221
- background: #11302294;
222
- padding: 10px;
321
+ background: #0f213fcf;
322
+ padding: 12px;
223
323
  display: grid;
224
324
  gap: 6px;
225
- color: #dfffe8;
325
+ transition:
326
+ border-color 0.2s ease,
327
+ box-shadow 0.2s ease,
328
+ background-color 0.2s ease;
329
+ }
330
+
331
+ .consent:hover {
332
+ border-color: #6ea4ef;
333
+ }
334
+
335
+ .consent.is-checked {
336
+ border-color: #22c55e;
337
+ background: #102f21d4;
338
+ box-shadow: inset 0 0 0 1px #22c55e33;
339
+ }
340
+
341
+ .consent-row {
342
+ display: grid;
343
+ grid-template-columns: 22px 1fr;
344
+ align-items: start;
345
+ gap: 10px;
346
+ margin: 0;
347
+ color: #deebff;
226
348
  font-size: 14px;
349
+ line-height: 1.5;
350
+ cursor: pointer;
351
+ }
352
+
353
+ .consent-row input {
354
+ margin: 0;
355
+ width: 18px;
356
+ height: 18px;
357
+ accent-color: #22c55e;
358
+ margin-top: 1px;
359
+ }
360
+
361
+ .consent-row a {
362
+ color: #a7ccff;
363
+ font-weight: 600;
364
+ }
365
+
366
+ .consent-row a:hover {
367
+ color: #d5e7ff;
368
+ }
369
+
370
+ .consent-error {
371
+ margin: 0;
372
+ color: #fecaca;
373
+ font-size: 12px;
374
+ }
375
+
376
+ html:not([data-login-has-wa='1']) #google-login-area {
377
+ display: none !important;
378
+ }
379
+
380
+ .summary {
381
+ border: 1px solid #2f9461bf;
382
+ border-radius: 12px;
383
+ background: linear-gradient(150deg, #113223cf, #0f2c1fd4);
384
+ padding: 12px;
385
+ display: grid;
386
+ gap: 4px;
387
+ color: #dcffe9;
388
+ font-size: 14px;
389
+ }
390
+
391
+ .summary-title {
392
+ margin: 0;
393
+ display: inline-flex;
394
+ align-items: center;
395
+ gap: 8px;
396
+ font-size: 13px;
397
+ font-weight: 700;
398
+ letter-spacing: 0.02em;
399
+ color: #b8f7d1;
400
+ }
401
+
402
+ .summary-title::before {
403
+ content: '';
404
+ width: 8px;
405
+ height: 8px;
406
+ border-radius: 50%;
407
+ background: #22c55e;
408
+ box-shadow: 0 0 0 4px #22c55e2b;
409
+ }
410
+
411
+ .summary[data-state='pending'] .summary-title::before {
412
+ background: #facc15;
413
+ box-shadow: 0 0 0 4px #facc152b;
227
414
  }
228
415
 
229
416
  .whatsapp-cta {
230
- border: 1px solid #2d7d57a8;
417
+ border: 1px solid #355d90bf;
231
418
  border-radius: 14px;
232
- background: #1130228f;
233
- padding: 12px;
419
+ background: linear-gradient(150deg, #0d1f3bcc, #12223fa8);
420
+ padding: 13px;
234
421
  display: grid;
235
- gap: 10px;
422
+ gap: 11px;
236
423
  }
237
424
 
238
425
  html[data-login-has-wa='1'] #whatsapp-cta {
@@ -241,28 +428,135 @@
241
428
 
242
429
  .whatsapp-cta p {
243
430
  margin: 0;
244
- color: #d5ffdf;
431
+ color: #d5e6ff;
245
432
  font-size: 14px;
246
433
  line-height: 1.5;
247
434
  }
248
435
 
249
436
  .btn.whatsapp {
250
- border-color: #1e9a5f;
251
- background: linear-gradient(90deg, #22c55e, #16a34a);
252
- color: #04230f;
437
+ border-color: #3a67a6;
438
+ background: #16315a;
439
+ color: #d9ebff;
253
440
  text-align: center;
254
441
  }
255
442
 
256
443
  .whatsapp-meta {
257
444
  margin: 0;
258
- color: #b7e9ca;
445
+ color: #9eb5d8;
259
446
  font-size: 13px;
260
447
  }
261
448
 
262
449
  .actions {
263
- display: flex;
264
- flex-wrap: wrap;
265
- gap: 8px;
450
+ display: grid;
451
+ gap: 10px;
452
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
453
+ }
454
+
455
+ .success-celebration {
456
+ position: fixed;
457
+ inset: 0;
458
+ z-index: 80;
459
+ display: grid;
460
+ place-items: center;
461
+ padding: 16px;
462
+ pointer-events: none;
463
+ opacity: 0;
464
+ visibility: hidden;
465
+ transition:
466
+ opacity 0.25s ease,
467
+ visibility 0.25s ease;
468
+ }
469
+
470
+ .success-celebration::before {
471
+ content: '';
472
+ position: absolute;
473
+ inset: 0;
474
+ background: radial-gradient(circle at center, #22c55e24 0%, #0b152bcc 52%, #070f20eb 100%);
475
+ backdrop-filter: blur(2px);
476
+ }
477
+
478
+ .success-celebration.is-visible {
479
+ opacity: 1;
480
+ visibility: visible;
481
+ }
482
+
483
+ .success-card {
484
+ position: relative;
485
+ width: min(360px, 100%);
486
+ border: 1px solid #4a76b4;
487
+ border-radius: 18px;
488
+ background: linear-gradient(155deg, #112241f0, #102238e8);
489
+ box-shadow:
490
+ 0 22px 40px #02091675,
491
+ inset 0 1px 0 #8cb8ff36;
492
+ padding: 18px 16px;
493
+ display: grid;
494
+ justify-items: center;
495
+ gap: 10px;
496
+ transform: translateY(18px) scale(0.95);
497
+ opacity: 0;
498
+ transition:
499
+ transform 0.35s cubic-bezier(0.2, 0.8, 0.2, 1),
500
+ opacity 0.35s ease;
501
+ }
502
+
503
+ .success-celebration.is-visible .success-card {
504
+ transform: translateY(0) scale(1);
505
+ opacity: 1;
506
+ }
507
+
508
+ .success-icon {
509
+ width: 76px;
510
+ height: 76px;
511
+ border-radius: 50%;
512
+ border: 1px solid #44c97a;
513
+ background: linear-gradient(140deg, #0e3122, #12492f);
514
+ display: grid;
515
+ place-items: center;
516
+ box-shadow:
517
+ 0 0 0 10px #22c55e14,
518
+ 0 10px 22px #22c55e3b;
519
+ }
520
+
521
+ .success-check-svg {
522
+ width: 34px;
523
+ height: 34px;
524
+ }
525
+
526
+ .success-check {
527
+ fill: none;
528
+ stroke: #ecfff3;
529
+ stroke-width: 2.6;
530
+ stroke-linecap: round;
531
+ stroke-linejoin: round;
532
+ stroke-dasharray: 40;
533
+ stroke-dashoffset: 40;
534
+ }
535
+
536
+ .success-celebration.is-visible .success-check {
537
+ animation: loginSuccessDraw 0.48s ease 0.12s forwards;
538
+ }
539
+
540
+ .success-title {
541
+ margin: 0;
542
+ font-family: 'Sora', sans-serif;
543
+ font-size: 20px;
544
+ font-weight: 700;
545
+ color: #effaf3;
546
+ letter-spacing: -0.02em;
547
+ }
548
+
549
+ .success-subtitle {
550
+ margin: 0;
551
+ font-size: 14px;
552
+ color: #c0d4f2;
553
+ text-align: center;
554
+ }
555
+
556
+ @keyframes loginSuccessDraw {
557
+ to {
558
+ stroke-dashoffset: 0;
559
+ }
266
560
  }
267
561
 
268
562
  @media (max-width: 620px) {
@@ -271,12 +565,27 @@
271
565
  }
272
566
 
273
567
  .content {
274
- padding: 18px 16px;
568
+ padding: 22px 16px 18px;
569
+ }
570
+
571
+ .card {
572
+ padding: 16px;
573
+ }
574
+
575
+ .actions {
576
+ grid-template-columns: 1fr;
577
+ }
578
+ }
579
+
580
+ @media (prefers-reduced-motion: reduce) {
581
+ .success-celebration,
582
+ .success-card {
583
+ transition: none;
275
584
  }
276
585
 
277
- .actions .btn {
278
- width: 100%;
279
- text-align: center;
586
+ .success-celebration.is-visible .success-check {
587
+ animation: none;
588
+ stroke-dashoffset: 0;
280
589
  }
281
590
  }
282
591
  </style>
@@ -291,37 +600,64 @@
291
600
  </header>
292
601
 
293
602
  <section class="content">
294
- <h1>Login da Plataforma</h1>
295
- <p class="lead">Entre com Google para vincular sua conta ao seu numero do WhatsApp e liberar os recursos web do OmniZap.</p>
603
+ <p class="eyebrow">Login seguro OmniZap</p>
604
+ <h1>Acesse sua conta</h1>
605
+ <p class="lead">Vincule seu WhatsApp e libere os recursos do OmniZap.</p>
296
606
 
297
- <article class="card">
298
- <p id="login-status" class="status">Carregando estado de login...</p>
607
+ <article id="login-main-card" class="card">
608
+ <p id="login-status" class="status">Verificando conta Google...</p>
299
609
  <p id="login-hint" class="hint"></p>
300
610
  <p id="login-error" class="error" hidden></p>
611
+ <div id="already-logged-banner" class="already-logged" hidden aria-live="polite" aria-atomic="true">
612
+ <p id="already-logged-title" class="already-logged-title">Voce ja esta logado neste navegador.</p>
613
+ <p id="already-logged-detail" class="already-logged-detail">Nao e necessario fazer login novamente. Escolha uma opcao abaixo.</p>
614
+ </div>
301
615
 
302
616
  <div id="google-login-area" class="google-area" hidden>
303
- <div data-google-login-button></div>
617
+ <div id="google-login-button-shell" class="google-button-shell" hidden>
618
+ <div data-google-login-button></div>
619
+ </div>
304
620
  <p id="google-login-state" class="google-state">Carregando login Google...</p>
305
- </div>
306
-
307
- <div id="login-summary" class="summary" hidden>
308
- <div id="login-summary-owner">WhatsApp vinculado:</div>
309
- </div>
310
-
311
- <div id="whatsapp-cta" class="whatsapp-cta" hidden>
312
- <p>Abriu esta página direto? Inicie a conversa no WhatsApp para gerar o link com seu número automaticamente.</p>
313
- <a id="whatsapp-cta-link" class="btn whatsapp" href="https://wa.me/?text=iniciar" target="_blank" rel="noreferrer noopener"> Abrir WhatsApp e enviar "iniciar" </a>
314
- <p id="whatsapp-cta-meta" class="whatsapp-meta"></p>
315
- </div>
316
-
317
- <div id="login-success-actions" class="actions" hidden>
318
- <a id="login-success-chat" class="btn primary" href="https://wa.me/?text=%2Fmenu" target="_blank" rel="noreferrer noopener"> Voltar ao chat do bot (/menu) </a>
319
- <a id="login-success-home" class="btn" href="/">Voltar para Home</a>
621
+ <div id="login-consent-box" class="consent">
622
+ <label class="consent-row" for="login-consent-checkbox">
623
+ <input id="login-consent-checkbox" type="checkbox" />
624
+ <span> Li e aceito os <a href="/termos-de-uso/" target="_blank" rel="noreferrer noopener">Termos de Uso</a> e a <a href="/termos-de-uso/#politica-de-privacidade" target="_blank" rel="noreferrer noopener">Politica de Privacidade</a>. </span>
625
+ </label>
626
+ <p id="login-consent-error" class="consent-error" hidden></p>
627
+ </div>
320
628
  </div>
321
629
  </article>
630
+
631
+ <div id="login-summary" class="summary" hidden>
632
+ <p id="login-summary-title" class="summary-title">WhatsApp conectado</p>
633
+ <div id="login-summary-owner"></div>
634
+ </div>
635
+
636
+ <div id="whatsapp-cta" class="whatsapp-cta" hidden>
637
+ <p>Para liberar o login neste navegador, inicie no WhatsApp e gere seu link seguro.</p>
638
+ <a id="whatsapp-cta-link" class="btn whatsapp" href="https://wa.me/?text=iniciar" target="_blank" rel="noreferrer noopener"> Gerar link de login no WhatsApp </a>
639
+ <p id="whatsapp-cta-meta" class="whatsapp-meta"></p>
640
+ </div>
641
+
642
+ <div id="login-success-actions" class="actions" hidden>
643
+ <a id="login-success-home" class="btn primary" href="/user/">Ir para o painel</a>
644
+ <a id="login-success-chat" class="btn" href="https://wa.me/?text=%2Fmenu" target="_blank" rel="noreferrer noopener">Abrir WhatsApp do bot</a>
645
+ </div>
322
646
  </section>
323
647
  </main>
324
648
 
325
- <script type="module" src="/js/apps/loginApp.js?v=20260228f"></script>
649
+ <div id="login-success-celebration" class="success-celebration" hidden aria-live="polite" aria-atomic="true">
650
+ <div class="success-card" role="status">
651
+ <div class="success-icon" aria-hidden="true">
652
+ <svg class="success-check-svg" viewBox="0 0 24 24" focusable="false">
653
+ <path class="success-check" d="M5 12.5l4.2 4.2L19 7.3" />
654
+ </svg>
655
+ </div>
656
+ <p class="success-title">Login concluido</p>
657
+ <p class="success-subtitle">Sua conta foi vinculada com sucesso.</p>
658
+ </div>
659
+ </div>
660
+
661
+ <script type="module" src="/js/apps/loginApp.js?v=20260301j"></script>
326
662
  </body>
327
663
  </html>