Ekimart commited on
Commit
7b2c9fb
·
1 Parent(s): 527670e

Supprimer le fichier `dashboard.html` obsolète et non utilisé.

Browse files
Files changed (1) hide show
  1. templates/dashboard.html +0 -1149
templates/dashboard.html DELETED
@@ -1,1149 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="fr">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>NotificationHub | Dashboard Professionnel</title>
7
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
- <style>
9
- :root {
10
- --primary: #5e35b1;
11
- --primary-dark: #4527a0;
12
- --secondary: #26a69a;
13
- --success: #43a047;
14
- --warning: #ff9800;
15
- --danger: #e53935;
16
- --dark: #263238;
17
- --light: #f5f7fa;
18
- --gray: #90a4ae;
19
- --card-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
20
- --transition: all 0.3s ease;
21
- }
22
-
23
- * {
24
- margin: 0;
25
- padding: 0;
26
- box-sizing: border-box;
27
- font-family: 'Segoe UI', 'Roboto', sans-serif;
28
- }
29
-
30
- body {
31
- background-color: #f0f4f8;
32
- color: #333;
33
- line-height: 1.6;
34
- min-height: 100vh;
35
- display: flex;
36
- flex-direction: column;
37
- }
38
-
39
- /* Header Styles */
40
- .header {
41
- background: linear-gradient(135deg, var(--primary), var(--primary-dark));
42
- color: white;
43
- padding: 1.5rem;
44
- display: flex;
45
- justify-content: space-between;
46
- align-items: center;
47
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
48
- position: sticky;
49
- top: 0;
50
- z-index: 100;
51
- }
52
-
53
- .logo {
54
- display: flex;
55
- align-items: center;
56
- gap: 0.8rem;
57
- }
58
-
59
- .logo i {
60
- font-size: 1.8rem;
61
- }
62
-
63
- .logo h1 {
64
- font-weight: 600;
65
- font-size: 1.6rem;
66
- }
67
-
68
- .user-controls {
69
- display: flex;
70
- align-items: center;
71
- gap: 1.5rem;
72
- }
73
-
74
- .theme-toggle {
75
- background: rgba(255, 255, 255, 0.15);
76
- border: none;
77
- border-radius: 50%;
78
- width: 40px;
79
- height: 40px;
80
- display: flex;
81
- align-items: center;
82
- justify-content: center;
83
- color: white;
84
- cursor: pointer;
85
- transition: var(--transition);
86
- }
87
-
88
- .theme-toggle:hover {
89
- background: rgba(255, 255, 255, 0.25);
90
- }
91
-
92
- .user-profile {
93
- display: flex;
94
- align-items: center;
95
- gap: 0.8rem;
96
- cursor: pointer;
97
- padding: 0.4rem 0.8rem;
98
- border-radius: 50px;
99
- transition: var(--transition);
100
- }
101
-
102
- .user-profile:hover {
103
- background: rgba(255, 255, 255, 0.15);
104
- }
105
-
106
- .avatar {
107
- width: 36px;
108
- height: 36px;
109
- border-radius: 50%;
110
- background: linear-gradient(135deg, var(--secondary), #00796b);
111
- display: flex;
112
- align-items: center;
113
- justify-content: center;
114
- font-weight: bold;
115
- color: white;
116
- }
117
-
118
- /* Main Layout */
119
- .main-container {
120
- display: flex;
121
- flex: 1;
122
- }
123
-
124
- /* Sidebar Styles */
125
- .sidebar {
126
- width: 260px;
127
- background: white;
128
- padding: 1.5rem 0;
129
- box-shadow: var(--card-shadow);
130
- transition: var(--transition);
131
- z-index: 90;
132
- }
133
-
134
- .nav-section {
135
- margin-bottom: 2rem;
136
- }
137
-
138
- .nav-title {
139
- padding: 0.5rem 1.5rem;
140
- font-size: 0.85rem;
141
- font-weight: 600;
142
- text-transform: uppercase;
143
- color: var(--gray);
144
- letter-spacing: 1px;
145
- }
146
-
147
- .nav-item {
148
- display: flex;
149
- align-items: center;
150
- gap: 0.8rem;
151
- padding: 0.9rem 1.5rem;
152
- color: var(--dark);
153
- text-decoration: none;
154
- transition: var(--transition);
155
- position: relative;
156
- font-weight: 500;
157
- }
158
-
159
- .nav-item:hover, .nav-item.active {
160
- background: rgba(94, 53, 177, 0.08);
161
- color: var(--primary);
162
- }
163
-
164
- .nav-item.active:before {
165
- content: '';
166
- position: absolute;
167
- left: 0;
168
- top: 0;
169
- height: 100%;
170
- width: 4px;
171
- background: var(--primary);
172
- border-radius: 0 4px 4px 0;
173
- }
174
-
175
- .nav-item i {
176
- font-size: 1.1rem;
177
- width: 24px;
178
- }
179
-
180
- /* Main Content */
181
- .content {
182
- flex: 1;
183
- padding: 2rem;
184
- display: flex;
185
- flex-direction: column;
186
- gap: 2rem;
187
- }
188
-
189
- .dashboard-grid {
190
- display: grid;
191
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
192
- gap: 1.5rem;
193
- }
194
-
195
- /* Card Styles */
196
- .card {
197
- background: white;
198
- border-radius: 16px;
199
- box-shadow: var(--card-shadow);
200
- overflow: hidden;
201
- transition: var(--transition);
202
- }
203
-
204
- .card:hover {
205
- transform: translateY(-5px);
206
- box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
207
- }
208
-
209
- .card-header {
210
- padding: 1.5rem 1.5rem 1rem;
211
- border-bottom: 1px solid rgba(0, 0, 0, 0.05);
212
- display: flex;
213
- justify-content: space-between;
214
- align-items: center;
215
- }
216
-
217
- .card-title {
218
- font-size: 1.2rem;
219
- font-weight: 600;
220
- color: var(--dark);
221
- display: flex;
222
- align-items: center;
223
- gap: 0.8rem;
224
- }
225
-
226
- .card-title i {
227
- color: var(--primary);
228
- }
229
-
230
- .card-actions {
231
- display: flex;
232
- gap: 0.5rem;
233
- }
234
-
235
- .card-actions button {
236
- background: none;
237
- border: none;
238
- color: var(--gray);
239
- cursor: pointer;
240
- padding: 0.4rem;
241
- border-radius: 8px;
242
- transition: var(--transition);
243
- }
244
-
245
- .card-actions button:hover {
246
- background: rgba(0, 0, 0, 0.05);
247
- color: var(--primary);
248
- }
249
-
250
- .card-body {
251
- padding: 1.5rem;
252
- }
253
-
254
- /* Status Indicator */
255
- .status-indicator {
256
- display: inline-flex;
257
- align-items: center;
258
- gap: 0.5rem;
259
- padding: 0.4rem 0.8rem;
260
- border-radius: 50px;
261
- font-size: 0.9rem;
262
- font-weight: 500;
263
- }
264
-
265
- .status-dot {
266
- width: 10px;
267
- height: 10px;
268
- border-radius: 50%;
269
- }
270
-
271
- .status-connected {
272
- background: var(--success);
273
- color: var(--success);
274
- }
275
-
276
- .status-disconnected {
277
- background: var(--danger);
278
- color: var(--danger);
279
- }
280
-
281
- /* Form Elements */
282
- .form-group {
283
- margin-bottom: 1.2rem;
284
- }
285
-
286
- .form-group label {
287
- display: block;
288
- margin-bottom: 0.5rem;
289
- font-weight: 500;
290
- color: var(--dark);
291
- font-size: 0.9rem;
292
- }
293
-
294
- .form-control {
295
- width: 100%;
296
- padding: 0.8rem 1rem;
297
- border: 1px solid #e0e0e0;
298
- border-radius: 10px;
299
- font-size: 1rem;
300
- transition: var(--transition);
301
- background: #fafafa;
302
- }
303
-
304
- .form-control:focus {
305
- outline: none;
306
- border-color: var(--primary);
307
- box-shadow: 0 0 0 3px rgba(94, 53, 177, 0.15);
308
- background: white;
309
- }
310
-
311
- .btn {
312
- padding: 0.8rem 1.5rem;
313
- border: none;
314
- border-radius: 10px;
315
- font-size: 0.95rem;
316
- font-weight: 600;
317
- cursor: pointer;
318
- transition: var(--transition);
319
- display: inline-flex;
320
- align-items: center;
321
- justify-content: center;
322
- gap: 0.5rem;
323
- }
324
-
325
- .btn-primary {
326
- background: linear-gradient(135deg, var(--primary), var(--primary-dark));
327
- color: white;
328
- }
329
-
330
- .btn-primary:hover {
331
- background: linear-gradient(135deg, var(--primary-dark), #311b92);
332
- box-shadow: 0 5px 15px rgba(94, 53, 177, 0.3);
333
- }
334
-
335
- .btn-secondary {
336
- background: #eceff1;
337
- color: var(--dark);
338
- }
339
-
340
- .btn-secondary:hover {
341
- background: #cfd8dc;
342
- }
343
-
344
- .btn-success {
345
- background: linear-gradient(135deg, var(--success), #2e7d32);
346
- color: white;
347
- }
348
-
349
- .btn-success:hover {
350
- background: linear-gradient(135deg, #2e7d32, #1b5e20);
351
- }
352
-
353
- .btn-danger {
354
- background: linear-gradient(135deg, var(--danger), #c62828);
355
- color: white;
356
- }
357
-
358
- .btn-danger:hover {
359
- background: linear-gradient(135deg, #c62828, #b71c1c);
360
- }
361
-
362
- .btn-group {
363
- display: flex;
364
- gap: 0.8rem;
365
- flex-wrap: wrap;
366
- }
367
-
368
- /* Messages Panel */
369
- .messages-panel {
370
- display: flex;
371
- flex-direction: column;
372
- height: 100%;
373
- }
374
-
375
- .messages {
376
- flex: 1;
377
- overflow-y: auto;
378
- border: 1px solid #e0e0e0;
379
- border-radius: 10px;
380
- padding: 1rem;
381
- background: #fafafa;
382
- margin-bottom: 1rem;
383
- display: flex;
384
- flex-direction: column;
385
- gap: 0.8rem;
386
- }
387
-
388
- .message {
389
- padding: 1rem;
390
- border-radius: 10px;
391
- border-left: 4px solid;
392
- background: white;
393
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.03);
394
- animation: fadeIn 0.3s ease;
395
- }
396
-
397
- @keyframes fadeIn {
398
- from {
399
- opacity: 0;
400
- transform: translateY(10px);
401
- }
402
- to {
403
- opacity: 1;
404
- transform: translateY(0);
405
- }
406
- }
407
-
408
- .message-header {
409
- display: flex;
410
- justify-content: space-between;
411
- margin-bottom: 0.5rem;
412
- font-size: 0.9rem;
413
- }
414
-
415
- .message-type {
416
- font-weight: 600;
417
- text-transform: capitalize;
418
- }
419
-
420
- .message-timestamp {
421
- color: var(--gray);
422
- font-size: 0.85rem;
423
- }
424
-
425
- .message-content {
426
- line-height: 1.5;
427
- }
428
-
429
- .message-system {
430
- border-left-color: var(--primary);
431
- }
432
-
433
- .message-notification {
434
- border-left-color: var(--secondary);
435
- }
436
-
437
- .message-error {
438
- border-left-color: var(--danger);
439
- }
440
-
441
- .message-success {
442
- border-left-color: var(--success);
443
- }
444
-
445
- .message-input-group {
446
- display: flex;
447
- gap: 0.8rem;
448
- }
449
-
450
- .message-input {
451
- flex: 1;
452
- padding: 0.8rem 1rem;
453
- border: 1px solid #e0e0e0;
454
- border-radius: 10px;
455
- font-size: 1rem;
456
- }
457
-
458
- /* Stats Cards */
459
- .stats-grid {
460
- display: grid;
461
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
462
- gap: 1.5rem;
463
- }
464
-
465
- .stat-card {
466
- display: flex;
467
- flex-direction: column;
468
- align-items: center;
469
- padding: 1.5rem;
470
- text-align: center;
471
- }
472
-
473
- .stat-icon {
474
- width: 60px;
475
- height: 60px;
476
- border-radius: 50%;
477
- display: flex;
478
- align-items: center;
479
- justify-content: center;
480
- font-size: 1.8rem;
481
- margin-bottom: 1rem;
482
- }
483
-
484
- .stat-value {
485
- font-size: 2rem;
486
- font-weight: 700;
487
- margin-bottom: 0.3rem;
488
- color: var(--dark);
489
- }
490
-
491
- .stat-label {
492
- color: var(--gray);
493
- font-size: 0.95rem;
494
- }
495
-
496
- /* Toast Notifications */
497
- .toast-container {
498
- position: fixed;
499
- bottom: 2rem;
500
- right: 2rem;
501
- z-index: 1000;
502
- display: flex;
503
- flex-direction: column;
504
- gap: 1rem;
505
- }
506
-
507
- .toast {
508
- min-width: 300px;
509
- padding: 1rem;
510
- border-radius: 12px;
511
- box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
512
- background: white;
513
- display: flex;
514
- align-items: flex-start;
515
- gap: 1rem;
516
- animation: slideIn 0.3s ease, fadeOut 0.5s ease 4.5s forwards;
517
- }
518
-
519
- @keyframes slideIn {
520
- from {
521
- transform: translateX(100%);
522
- opacity: 0;
523
- }
524
- to {
525
- transform: translateX(0);
526
- opacity: 1;
527
- }
528
- }
529
-
530
- @keyframes fadeOut {
531
- to {
532
- opacity: 0;
533
- }
534
- }
535
-
536
- .toast-icon {
537
- font-size: 1.5rem;
538
- margin-top: 0.2rem;
539
- }
540
-
541
- .toast-success .toast-icon {
542
- color: var(--success);
543
- }
544
-
545
- .toast-error .toast-icon {
546
- color: var(--danger);
547
- }
548
-
549
- .toast-info .toast-icon {
550
- color: var(--primary);
551
- }
552
-
553
- .toast-warning .toast-icon {
554
- color: var(--warning);
555
- }
556
-
557
- .toast-content {
558
- flex: 1;
559
- }
560
-
561
- .toast-title {
562
- font-weight: 600;
563
- margin-bottom: 0.3rem;
564
- }
565
-
566
- .toast-message {
567
- font-size: 0.9rem;
568
- color: #666;
569
- }
570
-
571
- .toast-close {
572
- background: none;
573
- border: none;
574
- color: var(--gray);
575
- cursor: pointer;
576
- font-size: 1.2rem;
577
- }
578
-
579
- /* Responsive Design */
580
- @media (max-width: 992px) {
581
- .sidebar {
582
- width: 80px;
583
- }
584
-
585
- .nav-title, .nav-item span {
586
- display: none;
587
- }
588
-
589
- .nav-item {
590
- justify-content: center;
591
- }
592
- }
593
-
594
- @media (max-width: 768px) {
595
- .main-container {
596
- flex-direction: column;
597
- }
598
-
599
- .sidebar {
600
- width: 100%;
601
- padding: 1rem;
602
- }
603
-
604
- .nav-list {
605
- display: flex;
606
- overflow-x: auto;
607
- gap: 0.5rem;
608
- }
609
-
610
- .nav-item {
611
- padding: 0.8rem;
612
- }
613
-
614
- .nav-title {
615
- display: none;
616
- }
617
- }
618
- </style>
619
- </head>
620
- <body>
621
- <!-- Header -->
622
- <header class="header">
623
- <div class="logo">
624
- <i class="fas fa-bell"></i>
625
- <h1>NotificationHub</h1>
626
- </div>
627
- <div class="user-controls">
628
- <button class="theme-toggle" id="themeToggle">
629
- <i class="fas fa-moon"></i>
630
- </button>
631
- <div class="user-profile">
632
- <div class="avatar">AD</div>
633
- <div>
634
- <div>Admin User</div>
635
- <small>Administrateur</small>
636
- </div>
637
- </div>
638
- </div>
639
- </header>
640
-
641
- <div class="main-container">
642
- <!-- Sidebar Navigation -->
643
- <nav class="sidebar">
644
- <div class="nav-section">
645
- <div class="nav-title">Navigation Principale</div>
646
- <div class="nav-list">
647
- <a href="#" class="nav-item active">
648
- <i class="fas fa-home"></i>
649
- <span>Dashboard</span>
650
- </a>
651
- <a href="#" class="nav-item">
652
- <i class="fas fa-bell"></i>
653
- <span>Notifications</span>
654
- </a>
655
- <a href="#" class="nav-item">
656
- <i class="fas fa-users"></i>
657
- <span>Clients</span>
658
- </a>
659
- <a href="#" class="nav-item">
660
- <i class="fas fa-chart-line"></i>
661
- <span>Statistiques</span>
662
- </a>
663
- <a href="#" class="nav-item">
664
- <i class="fas fa-cog"></i>
665
- <span>Paramètres</span>
666
- </a>
667
- </div>
668
- </div>
669
-
670
- <div class="nav-section">
671
- <div class="nav-title">Outils</div>
672
- <div class="nav-list">
673
- <a href="#" class="nav-item">
674
- <i class="fas fa-plug"></i>
675
- <span>Connexions</span>
676
- </a>
677
- <a href="#" class="nav-item">
678
- <i class="fas fa-history"></i>
679
- <span>Historique</span>
680
- </a>
681
- <a href="#" class="nav-item">
682
- <i class="fas fa-shield-alt"></i>
683
- <span>Sécurité</span>
684
- </a>
685
- </div>
686
- </div>
687
- </nav>
688
-
689
- <!-- Main Content -->
690
- <main class="content">
691
- <div class="dashboard-grid">
692
- <!-- Connection Panel -->
693
- <div class="card">
694
- <div class="card-header">
695
- <h2 class="card-title"><i class="fas fa-plug"></i> Connexion WebSocket</h2>
696
- </div>
697
- <div class="card-body">
698
- <div class="form-group">
699
- <label for="userId">Identifiant Utilisateur</label>
700
- <input type="text" id="userId" class="form-control" placeholder="user123" value="admin">
701
- </div>
702
-
703
- <div class="form-group">
704
- <label for="roles">Rôles (séparés par des virgules)</label>
705
- <input type="text" id="roles" class="form-control" placeholder="admin,user" value="admin">
706
- </div>
707
-
708
- <div class="form-group">
709
- <label>État de Connexion</label>
710
- <div class="status-indicator status-disconnected">
711
- <span class="status-dot"></span>
712
- <span id="statusText">Déconnecté</span>
713
- </div>
714
- </div>
715
-
716
- <div class="btn-group">
717
- <button class="btn btn-primary" onclick="connect()">
718
- <i class="fas fa-link"></i> Connecter
719
- </button>
720
- <button class="btn btn-secondary" onclick="disconnect()">
721
- <i class="fas fa-unlink"></i> Déconnecter
722
- </button>
723
- </div>
724
- </div>
725
- </div>
726
-
727
- <!-- Stats Panel -->
728
- <div class="card">
729
- <div class="card-header">
730
- <h2 class="card-title"><i class="fas fa-chart-bar"></i> Statistiques du Service</h2>
731
- <div class="card-actions">
732
- <button title="Actualiser" onclick="getStats()">
733
- <i class="fas fa-sync-alt"></i>
734
- </button>
735
- </div>
736
- </div>
737
- <div class="card-body">
738
- <div class="stats-grid">
739
- <div class="stat-card">
740
- <div class="stat-icon" style="background: rgba(67, 160, 71, 0.1); color: #43a047;">
741
- <i class="fas fa-users"></i>
742
- </div>
743
- <div class="stat-value" id="connectedClients">0</div>
744
- <div class="stat-label">Clients Connectés</div>
745
- </div>
746
-
747
- <div class="stat-card">
748
- <div class="stat-icon" style="background: rgba(94, 53, 177, 0.1); color: #5e35b1;">
749
- <i class="fas fa-bell"></i>
750
- </div>
751
- <div class="stat-value" id="totalNotifications">0</div>
752
- <div class="stat-label">Notifications</div>
753
- </div>
754
-
755
- <div class="stat-card">
756
- <div class="stat-icon" style="background: rgba(38, 166, 154, 0.1); color: #26a69a;">
757
- <i class="fas fa-list"></i>
758
- </div>
759
- <div class="stat-value" id="activeSubscriptions">0</div>
760
- <div class="stat-label">Abonnements</div>
761
- </div>
762
- </div>
763
- </div>
764
- </div>
765
- </div>
766
-
767
- <!-- Messages Panel -->
768
- <div class="card">
769
- <div class="card-header">
770
- <h2 class="card-title"><i class="fas fa-comments"></i> Messages en Temps Réel</h2>
771
- <div class="card-actions">
772
- <button title="Effacer" onclick="clearMessages()">
773
- <i class="fas fa-trash-alt"></i>
774
- </button>
775
- <button title="Clients" onclick="getClients()">
776
- <i class="fas fa-users"></i>
777
- </button>
778
- </div>
779
- </div>
780
- <div class="card-body">
781
- <div class="messages-panel">
782
- <div class="messages" id="messages">
783
- <!-- Messages will appear here -->
784
- </div>
785
-
786
- <div class="message-input-group">
787
- <input type="text" id="messageInput" class="message-input" placeholder="Tapez votre message...">
788
- <button class="btn btn-primary" onclick="sendMessage()">
789
- <i class="fas fa-paper-plane"></i> Envoyer
790
- </button>
791
- </div>
792
- </div>
793
- </div>
794
- </div>
795
-
796
- <!-- API Test Panel -->
797
- <div class="card">
798
- <div class="card-header">
799
- <h2 class="card-title"><i class="fas fa-bolt"></i> Tester les Notifications</h2>
800
- </div>
801
- <div class="card-body">
802
- <div class="dashboard-grid">
803
- <!-- User Notification -->
804
- <div class="card">
805
- <div class="card-header">
806
- <h3 class="card-title"><i class="fas fa-user"></i> À un Utilisateur</h3>
807
- </div>
808
- <div class="card-body">
809
- <div class="form-group">
810
- <label>ID Utilisateur</label>
811
- <input type="text" class="form-control" id="targetUserId" value="user123">
812
- </div>
813
- <button class="btn btn-primary" onclick="sendUserNotification()">
814
- <i class="fas fa-paper-plane"></i> Envoyer Notification
815
- </button>
816
- </div>
817
- </div>
818
-
819
- <!-- Role Notification -->
820
- <div class="card">
821
- <div class="card-header">
822
- <h3 class="card-title"><i class="fas fa-user-tag"></i> À un Rôle</h3>
823
- </div>
824
- <div class="card-body">
825
- <div class="form-group">
826
- <label>Rôle</label>
827
- <input type="text" class="form-control" id="targetRole" value="admin">
828
- </div>
829
- <button class="btn btn-primary" onclick="sendRoleNotification()">
830
- <i class="fas fa-paper-plane"></i> Envoyer Notification
831
- </button>
832
- </div>
833
- </div>
834
-
835
- <!-- Broadcast -->
836
- <div class="card">
837
- <div class="card-header">
838
- <h3 class="card-title"><i class="fas fa-bullhorn"></i> Diffusion Globale</h3>
839
- </div>
840
- <div class="card-body">
841
- <button class="btn btn-success" onclick="sendBroadcast()">
842
- <i class="fas fa-broadcast-tower"></i> Diffuser à Tous
843
- </button>
844
- </div>
845
- </div>
846
- </div>
847
- </div>
848
- </div>
849
- </main>
850
- </div>
851
-
852
- <!-- Toast Container -->
853
- <div class="toast-container" id="toastContainer"></div>
854
-
855
- <script>
856
- // Global variables
857
- let ws = null;
858
- let baseUrl = window.location.origin;
859
- let isDarkMode = false;
860
-
861
- // DOM Elements
862
- const statusIndicator = document.querySelector('.status-indicator');
863
- const statusText = document.getElementById('statusText');
864
- const themeToggle = document.getElementById('themeToggle');
865
-
866
- // Initialize
867
- document.addEventListener('DOMContentLoaded', function () {
868
- // Set initial theme
869
- if (localStorage.getItem('darkMode') === 'true') {
870
- toggleDarkMode();
871
- }
872
-
873
- // Connect automatically
874
- setTimeout(connect, 1000);
875
-
876
- // Setup event listeners
877
- themeToggle.addEventListener('click', toggleDarkMode);
878
- document.getElementById('messageInput').addEventListener('keypress', function (e) {
879
- if (e.key === 'Enter') sendMessage();
880
- });
881
- });
882
-
883
- // Toggle dark mode
884
- function toggleDarkMode() {
885
- isDarkMode = !isDarkMode;
886
- document.body.classList.toggle('dark-mode', isDarkMode);
887
- localStorage.setItem('darkMode', isDarkMode);
888
-
889
- themeToggle.innerHTML = isDarkMode ?
890
- '<i class="fas fa-sun"></i>' :
891
- '<i class="fas fa-moon"></i>';
892
-
893
- themeToggle.title = isDarkMode ?
894
- 'Passer en mode clair' :
895
- 'Passer en mode sombre';
896
- }
897
-
898
- // Connection functions
899
- function connect() {
900
- const userId = document.getElementById('userId').value;
901
- const roles = document.getElementById('roles').value;
902
- const protocol = window.location.protocol === "https:" ? "wss" : "ws";
903
- const url = `${protocol}://${window.location.host}/ws/${userId}?roles=${roles}`;
904
-
905
- ws = new WebSocket(url);
906
-
907
- ws.onmessage = function (event) {
908
- const data = JSON.parse(event.data);
909
- addMessage(data, 'notification');
910
-
911
- // Show toast notification
912
- showToast(
913
- 'Nouvelle Notification',
914
- data.message || data.content || 'Notification reçue',
915
- 'info'
916
- );
917
- };
918
-
919
- ws.onopen = function () {
920
- updateConnectionStatus(true);
921
- addMessage({message: 'Connexion WebSocket établie', type: 'system'}, 'system');
922
- getStats();
923
-
924
- showToast(
925
- 'Connexion réussie',
926
- 'Vous êtes maintenant connecté au service WebSocket',
927
- 'success'
928
- );
929
- };
930
-
931
- ws.onclose = function () {
932
- updateConnectionStatus(false);
933
- addMessage({message: 'Connexion WebSocket fermée', type: 'system'}, 'system');
934
-
935
- showToast(
936
- 'Déconnecté',
937
- 'La connexion WebSocket a été fermée',
938
- 'warning'
939
- );
940
- };
941
-
942
- ws.onerror = function (error) {
943
- addMessage({message: 'Erreur WebSocket: ' + error, type: 'error'}, 'error');
944
-
945
- showToast(
946
- 'Erreur de connexion',
947
- 'Impossible de se connecter au service WebSocket',
948
- 'error'
949
- );
950
- };
951
- }
952
-
953
- function disconnect() {
954
- if (ws) {
955
- ws.close();
956
- ws = null;
957
- updateConnectionStatus(false);
958
- }
959
- }
960
-
961
- function updateConnectionStatus(connected) {
962
- if (connected) {
963
- statusIndicator.classList.remove('status-disconnected');
964
- statusIndicator.classList.add('status-connected');
965
- statusText.textContent = 'Connecté';
966
- } else {
967
- statusIndicator.classList.remove('status-connected');
968
- statusIndicator.classList.add('status-disconnected');
969
- statusText.textContent = 'Déconnecté';
970
- }
971
- }
972
-
973
- // Messaging functions
974
- function sendMessage() {
975
- if (ws && ws.readyState === WebSocket.OPEN) {
976
- const message = document.getElementById('messageInput').value;
977
- if (message.trim()) {
978
- ws.send(JSON.stringify({message: message}));
979
- document.getElementById('messageInput').value = '';
980
- }
981
- } else {
982
- addMessage({message: 'Connexion WebSocket non établie', type: 'error'}, 'error');
983
- }
984
- }
985
-
986
- function addMessage(data, type) {
987
- const messages = document.getElementById('messages');
988
- const messageDiv = document.createElement('div');
989
- messageDiv.className = `message message-${type}`;
990
-
991
- const timestamp = new Date().toLocaleTimeString();
992
- const content = data.message || JSON.stringify(data, null, 2);
993
-
994
- messageDiv.innerHTML = `
995
- <div class="message-header">
996
- <span class="message-type">${type}</span>
997
- <span class="message-timestamp">${timestamp}</span>
998
- </div>
999
- <div class="message-content">${content}</div>
1000
- `;
1001
-
1002
- messages.appendChild(messageDiv);
1003
- messages.scrollTop = messages.scrollHeight;
1004
- }
1005
-
1006
- function clearMessages() {
1007
- document.getElementById('messages').innerHTML = '';
1008
- }
1009
-
1010
- // Notification functions
1011
- function sendUserNotification() {
1012
- const userId = document.getElementById('targetUserId').value;
1013
- const message = {
1014
- type: "info",
1015
- title: "Test Utilisateur",
1016
- content: "Ceci est un message de test pour un utilisateur spécifique"
1017
- };
1018
-
1019
- // Simulated API call
1020
- addMessage({
1021
- message: `Notification envoyée à l'utilisateur ${userId}`,
1022
- details: message
1023
- }, 'success');
1024
-
1025
- showToast(
1026
- 'Notification envoyée',
1027
- `À l'utilisateur: ${userId}`,
1028
- 'success'
1029
- );
1030
- }
1031
-
1032
- function sendRoleNotification() {
1033
- const role = document.getElementById('targetRole').value;
1034
- const message = {
1035
- type: "warning",
1036
- title: "Alerte Rôle",
1037
- content: "Message important pour les membres de ce rôle"
1038
- };
1039
-
1040
- // Simulated API call
1041
- addMessage({
1042
- message: `Notification envoyée au rôle ${role}`,
1043
- details: message
1044
- }, 'success');
1045
-
1046
- showToast(
1047
- 'Notification envoyée',
1048
- `Au rôle: ${role}`,
1049
- 'success'
1050
- );
1051
- }
1052
-
1053
- function sendBroadcast() {
1054
- const message = {
1055
- type: "announcement",
1056
- title: "Annonce Globale",
1057
- content: "Message diffusé à tous les clients connectés"
1058
- };
1059
-
1060
- // Simulated API call
1061
- addMessage({
1062
- message: "Notification diffusée à tous les clients",
1063
- details: message
1064
- }, 'success');
1065
-
1066
- showToast(
1067
- 'Diffusion globale',
1068
- 'Notification envoyée à tous les clients',
1069
- 'success'
1070
- );
1071
- }
1072
-
1073
- // Stats functions
1074
- function getStats() {
1075
- // Simulated data
1076
- const stats = {
1077
- connected_clients: Math.floor(Math.random() * 100),
1078
- total_notifications: Math.floor(Math.random() * 500),
1079
- active_subscriptions: Math.floor(Math.random() * 50)
1080
- };
1081
-
1082
- document.getElementById('connectedClients').textContent = stats.connected_clients;
1083
- document.getElementById('totalNotifications').textContent = stats.total_notifications;
1084
- document.getElementById('activeSubscriptions').textContent = stats.active_subscriptions;
1085
-
1086
- addMessage({
1087
- message: "Statistiques mises à jour",
1088
- details: stats
1089
- }, 'system');
1090
- }
1091
-
1092
- function getClients() {
1093
- // Simulated data
1094
- const clients = [
1095
- {id: "user123", roles: ["user"], connected: true},
1096
- {id: "admin", roles: ["admin", "user"], connected: true},
1097
- {id: "guest", roles: ["guest"], connected: true}
1098
- ];
1099
-
1100
- addMessage({
1101
- message: "Clients connectés récupérés",
1102
- clients: clients
1103
- }, 'system');
1104
-
1105
- showToast(
1106
- 'Clients connectés',
1107
- `${clients.length} clients actuellement connectés`,
1108
- 'info'
1109
- );
1110
- }
1111
-
1112
- // Toast notification function
1113
- function showToast(title, message, type) {
1114
- const toastContainer = document.getElementById('toastContainer');
1115
- const toast = document.createElement('div');
1116
- toast.className = `toast toast-${type}`;
1117
-
1118
- toast.innerHTML = `
1119
- <div class="toast-icon">
1120
- <i class="fas fa-${type === 'error' ? 'exclamation-circle' :
1121
- type === 'warning' ? 'exclamation-triangle' :
1122
- type === 'success' ? 'check-circle' : 'info-circle'}"></i>
1123
- </div>
1124
- <div class="toast-content">
1125
- <div class="toast-title">${title}</div>
1126
- <div class="toast-message">${message}</div>
1127
- </div>
1128
- <button class="toast-close">
1129
- <i class="fas fa-times"></i>
1130
- </button>
1131
- `;
1132
-
1133
- toastContainer.appendChild(toast);
1134
-
1135
- // Remove toast on close button click
1136
- toast.querySelector('.toast-close').addEventListener('click', function () {
1137
- toast.remove();
1138
- });
1139
-
1140
- // Auto-remove toast after 5 seconds
1141
- setTimeout(() => {
1142
- if (toast.parentNode) {
1143
- toast.remove();
1144
- }
1145
- }, 5000);
1146
- }
1147
- </script>
1148
- </body>
1149
- </html>