melassy commited on
Commit
cdeebf8
·
verified ·
1 Parent(s): cdcf27a

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +419 -66
index.html CHANGED
@@ -5,6 +5,7 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>نظام إرسال رسائل الواتساب للطلاب</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-color: #25D366;
@@ -15,6 +16,7 @@
15
  --white: #ffffff;
16
  --error-color: #ff4444;
17
  --success-color: #00C851;
 
18
  }
19
 
20
  * {
@@ -82,6 +84,7 @@
82
  border-radius: 8px;
83
  transition: all 0.3s;
84
  background-color: var(--light-bg);
 
85
  }
86
 
87
  .upload-container:hover {
@@ -89,6 +92,16 @@
89
  background-color: rgba(52, 183, 241, 0.05);
90
  }
91
 
 
 
 
 
 
 
 
 
 
 
92
  .upload-container i {
93
  font-size: 48px;
94
  color: var(--accent-color);
@@ -214,6 +227,48 @@
214
  font-size: 18px;
215
  }
216
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  .modal {
218
  display: none;
219
  position: fixed;
@@ -290,6 +345,10 @@
290
  color: var(--success-color);
291
  }
292
 
 
 
 
 
293
  .template-tags {
294
  display: flex;
295
  flex-wrap: wrap;
@@ -312,6 +371,7 @@
312
  color: var(--white);
313
  }
314
 
 
315
  @media (max-width: 768px) {
316
  .container {
317
  padding: 15px;
@@ -329,6 +389,16 @@
329
  padding: 10px 20px;
330
  font-size: 14px;
331
  }
 
 
 
 
 
 
 
 
 
 
332
  }
333
  </style>
334
  </head>
@@ -355,12 +425,24 @@
355
  <i class="fas fa-folder-open"></i> اختر ملف
356
  </button>
357
  </div>
 
 
 
 
 
 
 
 
 
 
 
358
  <div id="fileInfo" style="margin-top: 15px; display: none;">
359
  <div class="file-details" style="display: flex; align-items: center;">
360
  <i class="fas fa-file-excel" style="color: var(--success-color); font-size: 24px; margin-left: 10px;"></i>
361
  <div>
362
  <p style="font-weight: 600; margin-bottom: 5px;" id="fileName"></p>
363
  <p style="color: #666; font-size: 14px;" id="fileSize"></p>
 
364
  </div>
365
  <button id="clearFileBtn" style="background: none; border: none; margin-right: auto; color: var(--error-color); cursor: pointer;">
366
  <i class="fas fa-times"></i>
@@ -390,6 +472,7 @@
390
  <div class="preview-section">
391
  <div class="preview-header">
392
  <h3><i class="fas fa-eye"></i> معاينة الرسائل</h3>
 
393
  </div>
394
  <div class="preview-content">
395
  <p id="previewMessage">سيتم عرض معاينة الرسائل هنا بعد تحميل الملف وإدخال نموذج الرسالة.</p>
@@ -402,6 +485,7 @@
402
  <button class="btn send-btn" id="sendMessagesBtn" disabled>
403
  <i class="fab fa-whatsapp"></i> إرسال الرسائل
404
  </button>
 
405
  </section>
406
  </div>
407
  </div>
@@ -423,6 +507,9 @@
423
  </div>
424
  </div>
425
 
 
 
 
426
  <div style="text-align: center;">
427
  <button class="btn btn-secondary" id="cancelSendingBtn">
428
  <i class="fas fa-stop"></i> إلغاء العملية
@@ -441,12 +528,36 @@
441
 
442
  <div style="margin: 20px 0; text-align: center;">
443
  <p id="successMessage"></p>
 
444
  </div>
445
 
446
  <div style="text-align: center;">
447
  <button class="btn" id="okSuccessBtn">
448
  <i class="fas fa-check"></i> حسناً
449
  </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
  </div>
451
  </div>
452
  </div>
@@ -460,24 +571,38 @@
460
  const fileInfo = document.getElementById('fileInfo');
461
  const fileName = document.getElementById('fileName');
462
  const fileSize = document.getElementById('fileSize');
 
463
  const clearFileBtn = document.getElementById('clearFileBtn');
464
  const messageTemplate = document.getElementById('messageTemplate');
465
  const customLink = document.getElementById('customLink');
466
  const previewMessage = document.getElementById('previewMessage');
 
467
  const studentList = document.getElementById('studentList');
468
  const sendMessagesBtn = document.getElementById('sendMessagesBtn');
 
469
  const progressModal = document.getElementById('progressModal');
470
  const progressBar = document.getElementById('progressBar');
471
  const statusMessage = document.getElementById('statusMessage');
 
 
472
  const closeModalBtn = document.getElementById('closeModalBtn');
473
  const cancelSendingBtn = document.getElementById('cancelSendingBtn');
474
  const successModal = document.getElementById('successModal');
475
  const successMessage = document.getElementById('successMessage');
 
476
  const okSuccessBtn = document.getElementById('okSuccessBtn');
 
 
 
 
 
 
477
 
478
  // Variables
479
  let studentsData = [];
480
  let sendingProcess = null;
 
 
481
 
482
  // Event Listeners
483
  selectFileBtn.addEventListener('click', function() {
@@ -486,19 +611,16 @@
486
 
487
  uploadContainer.addEventListener('dragover', function(e) {
488
  e.preventDefault();
489
- uploadContainer.style.borderColor = var('--accent-color');
490
- uploadContainer.style.backgroundColor = 'rgba(52, 183, 241, 0.1)';
491
  });
492
 
493
  uploadContainer.addEventListener('dragleave', function() {
494
- uploadContainer.style.borderColor = '#ccc';
495
- uploadContainer.style.backgroundColor = 'var(--light-bg)';
496
  });
497
 
498
  uploadContainer.addEventListener('drop', function(e) {
499
  e.preventDefault();
500
- uploadContainer.style.borderColor = '#ccc';
501
- uploadContainer.style.backgroundColor = 'var(--light-bg)';
502
 
503
  if (e.dataTransfer.files.length) {
504
  fileInput.files = e.dataTransfer.files;
@@ -509,15 +631,12 @@
509
  fileInput.addEventListener('change', handleFileUpload);
510
 
511
  clearFileBtn.addEventListener('click', function() {
512
- fileInput.value = '';
513
- fileInfo.style.display = 'none';
514
- studentsData = [];
515
- updatePreview();
516
- updateSendButtonState();
517
  });
518
 
519
  messageTemplate.addEventListener('input', function() {
520
  updatePreview();
 
521
  });
522
 
523
  customLink.addEventListener('input', function() {
@@ -533,8 +652,12 @@
533
  cancelSendingBtn.addEventListener('click', function() {
534
  if (sendingProcess) {
535
  clearInterval(sendingProcess);
536
- statusMessage.innerHTML = '<span class="error">تم إيقاف عملية الإرسال</span>';
 
537
  cancelSendingBtn.disabled = true;
 
 
 
538
  }
539
  });
540
 
@@ -542,6 +665,19 @@
542
  successModal.style.display = 'none';
543
  });
544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  // Add event listeners for template tags
546
  document.querySelectorAll('.tag').forEach(tag => {
547
  tag.addEventListener('click', function() {
@@ -556,52 +692,154 @@
556
  const file = fileInput.files[0];
557
  if (!file) return;
558
 
559
- // Simulate file processing (in a real app, you'd use SheetJS or similar)
560
- setTimeout(() => {
561
- studentsData = generateSampleData();
562
-
563
- fileName.textContent = file.name;
564
- fileSize.textContent = formatFileSize(file.size);
565
- fileInfo.style.display = 'block';
566
-
567
- updatePreview();
568
- updateSendButtonState();
569
- }, 500);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
570
  }
571
 
572
- function generateSampleData() {
573
- // In a real app, you would parse the actual Excel file
574
- const mockData = [];
575
- const names = [
576
- "أحمد محمد", "فاطمة علي", "يوسف إبراهيم",
577
- "سارة خالد", "محمد حسن", "نورا عبدالله",
578
- "عمر كمال", "لمى سعيد", "خالد وليد",
579
- "هناء مصطفى", "حسين رضا", "آية محمود"
580
- ];
 
 
 
 
 
 
581
 
582
- for (let i = 0; i < 12; i++) {
583
- mockData.push({
584
- name: names[i],
585
- phone: `9665${Math.floor(10000000 + Math.random() * 90000000)}`
586
- });
 
587
  }
588
 
589
- return mockData;
 
 
 
 
 
590
  }
591
 
592
  function formatFileSize(bytes) {
593
- if (bytes === 0) return '0 Bytes';
594
  const k = 1024;
595
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
596
  const i = Math.floor(Math.log(bytes) / Math.log(k));
597
  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
598
  }
599
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  function updatePreview() {
601
  if (studentsData.length === 0) {
602
  studentList.style.display = 'none';
603
  previewMessage.style.display = 'block';
604
  previewMessage.textContent = 'سيتم عرض معاينة الرسائل هنا بعد تحميل الملف وإدخال نموذج الرسالة.';
 
605
  return;
606
  }
607
 
@@ -610,16 +848,18 @@
610
  studentList.style.display = 'none';
611
  previewMessage.style.display = 'block';
612
  previewMessage.textContent = 'الرجاء إدخال نموذج الرسالة لمعاينة الرسائل.';
 
613
  return;
614
  }
615
 
616
  studentList.innerHTML = '';
617
  previewMessage.style.display = 'none';
618
  studentList.style.display = 'block';
 
619
 
620
- // Show preview for first 3 students
621
- const previewCount = Math.min(3, studentsData.length);
622
- for (let i = 0; i < previewCount; i++) {
623
  const student = studentsData[i];
624
  const link = customLink.value || '{الرابط}';
625
  const processedMessage = processMessage(message, student.name, link);
@@ -629,7 +869,7 @@
629
  li.innerHTML = `
630
  <div style="flex: 1;">
631
  <strong>${student.name}</strong>
632
- <div style="font-size: 12px; color: #666; margin-top: 4px;">${student.phone}</div>
633
  </div>
634
  <div style="max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
635
  ${processedMessage}
@@ -638,16 +878,24 @@
638
  studentList.appendChild(li);
639
  }
640
 
641
- if (studentsData.length > 3) {
642
  const li = document.createElement('li');
643
  li.className = 'student-item';
644
  li.style.textAlign = 'center';
645
  li.style.color = '#666';
646
- li.textContent = `و ${studentsData.length - 3} طلاب آخرين...`;
647
  studentList.appendChild(li);
648
  }
649
  }
650
 
 
 
 
 
 
 
 
 
651
  function processMessage(template, name, link) {
652
  const today = new Date();
653
  const dateStr = `${today.getDate()}/${today.getMonth() + 1}/${today.getFullYear()}`;
@@ -655,7 +903,7 @@
655
  return template
656
  .replace(/{اسم الطالب}/g, name)
657
  .replace(/{الرابط}/g, link)
658
- .replace(/{الرقم}/g, '+9665XXXXXX')
659
  .replace(/{التاريخ}/g, dateStr);
660
  }
661
 
@@ -663,6 +911,14 @@
663
  sendMessagesBtn.disabled = studentsData.length === 0 || !messageTemplate.value;
664
  }
665
 
 
 
 
 
 
 
 
 
666
  function insertAtCursor(textarea, text) {
667
  const startPos = textarea.selectionStart;
668
  const endPos = textarea.selectionEnd;
@@ -680,46 +936,140 @@
680
  }
681
 
682
  function startSendingProcess() {
 
 
 
 
 
 
 
683
  progressModal.style.display = 'flex';
684
  progressBar.style.width = '0%';
 
 
685
  cancelSendingBtn.disabled = false;
686
 
687
- let progress = 0;
688
  const totalStudents = studentsData.length;
689
  const link = customLink.value || '{الرابط}';
 
690
 
691
  sendingProcess = setInterval(() => {
692
- if (progress >= totalStudents) {
 
693
  clearInterval(sendingProcess);
694
  sendingProcess = null;
695
 
696
  // Show success message
697
  progressModal.style.display = 'none';
698
- successMessage.textContent = `تم إرسال ${totalStudents} رسالة بنجاح إلى الطلاب.`;
 
 
 
 
 
 
 
699
  successModal.style.display = 'flex';
700
  return;
701
  }
702
 
703
- progress++;
704
- const percent = Math.round((progress / totalStudents) * 100);
705
- progressBar.style.width = `${percent}%`;
706
-
707
- // Simulate sending message (in a real app, you would send via WhatsApp API)
708
- const currentStudent = studentsData[progress - 1];
709
- const message = processMessage(messageTemplate.value, currentStudent.name, link);
710
 
711
- statusMessage.innerHTML = `جاري إرسال الرسالة إلى <strong>${currentStudent.name}</strong>...`;
 
 
 
712
 
713
- // Randomly simulate failures (for demo purposes)
714
- if (Math.random() < 0.1 && progress < totalStudents) {
715
- setTimeout(() => {
716
- statusMessage.innerHTML = `<span class="error">فشل إرسال الرسالة إلى ${currentStudent.name} - سيتم إعادة المحاولة...</span>`;
717
- progress--; // Retry this one
718
- }, 1500);
719
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
720
  }, 1500);
721
  }
722
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723
  // Handle clicks outside modal to close it
724
  window.addEventListener('click', function(event) {
725
  if (event.target === progressModal) {
@@ -728,8 +1078,11 @@
728
  if (event.target === successModal) {
729
  successModal.style.display = 'none';
730
  }
 
 
 
731
  });
732
  });
733
  </script>
734
- <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: absolute; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">This website has been generated by <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
735
  </html>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>نظام إرسال رسائل الواتساب للطلاب</title>
7
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
9
  <style>
10
  :root {
11
  --primary-color: #25D366;
 
16
  --white: #ffffff;
17
  --error-color: #ff4444;
18
  --success-color: #00C851;
19
+ --warning-color: #ffbb33;
20
  }
21
 
22
  * {
 
84
  border-radius: 8px;
85
  transition: all 0.3s;
86
  background-color: var(--light-bg);
87
+ position: relative;
88
  }
89
 
90
  .upload-container:hover {
 
92
  background-color: rgba(52, 183, 241, 0.05);
93
  }
94
 
95
+ .upload-container.active {
96
+ border-color: var(--primary-color);
97
+ background-color: rgba(37, 211, 102, 0.05);
98
+ }
99
+
100
+ .upload-container.error {
101
+ border-color: var(--error-color);
102
+ background-color: rgba(255, 68, 68, 0.05);
103
+ }
104
+
105
  .upload-container i {
106
  font-size: 48px;
107
  color: var(--accent-color);
 
227
  font-size: 18px;
228
  }
229
 
230
+ /* File Requirements Info */
231
+ .file-requirements {
232
+ background-color: rgba(52, 183, 241, 0.1);
233
+ border-left: 4px solid var(--accent-color);
234
+ padding: 12px 15px;
235
+ margin-top: 15px;
236
+ border-radius: 4px;
237
+ font-size: 14px;
238
+ }
239
+
240
+ .file-requirements h4 {
241
+ margin-bottom: 8px;
242
+ color: var(--secondary-color);
243
+ }
244
+
245
+ .file-requirements ul {
246
+ list-style-position: inside;
247
+ padding-right: 10px;
248
+ }
249
+
250
+ .file-requirements li {
251
+ margin-bottom: 5px;
252
+ }
253
+
254
+ /* Loading Animation */
255
+ .spinner {
256
+ width: 24px;
257
+ height: 24px;
258
+ border: 3px solid rgba(255,255,255,0.3);
259
+ border-radius: 50%;
260
+ border-top-color: var(--white);
261
+ animation: spin 1s ease-in-out infinite;
262
+ display: inline-block;
263
+ vertical-align: middle;
264
+ margin-left: 8px;
265
+ }
266
+
267
+ @keyframes spin {
268
+ to { transform: rotate(360deg); }
269
+ }
270
+
271
+ /* Modals */
272
  .modal {
273
  display: none;
274
  position: fixed;
 
345
  color: var(--success-color);
346
  }
347
 
348
+ .warning {
349
+ color: var(--warning-color);
350
+ }
351
+
352
  .template-tags {
353
  display: flex;
354
  flex-wrap: wrap;
 
371
  color: var(--white);
372
  }
373
 
374
+ /* Responsive */
375
  @media (max-width: 768px) {
376
  .container {
377
  padding: 15px;
 
389
  padding: 10px 20px;
390
  font-size: 14px;
391
  }
392
+
393
+ .student-item {
394
+ flex-direction: column;
395
+ align-items: flex-start;
396
+ }
397
+
398
+ .student-item div:nth-child(2) {
399
+ margin-top: 8px;
400
+ max-width: 100%;
401
+ }
402
  }
403
  </style>
404
  </head>
 
425
  <i class="fas fa-folder-open"></i> اختر ملف
426
  </button>
427
  </div>
428
+
429
+ <div class="file-requirements">
430
+ <h4><i class="fas fa-info-circle"></i> متطلبات الملف:</h4>
431
+ <ul>
432
+ <li>يجب أن يكون الملف من نوع Excel (xlsx, xls) أو CSV</li>
433
+ <li>يجب أن يحتوي على عمود باسم "الاسم" أو "اسم الطالب"</li>
434
+ <li>يجب أن يحتوي على عمود باسم "رقم الجوال" أو "الهاتف"</li>
435
+ <li>يمكنك <a href="#" id="downloadSample">تحميل نموذج</a> لاستخدامه كمرجع</li>
436
+ </ul>
437
+ </div>
438
+
439
  <div id="fileInfo" style="margin-top: 15px; display: none;">
440
  <div class="file-details" style="display: flex; align-items: center;">
441
  <i class="fas fa-file-excel" style="color: var(--success-color); font-size: 24px; margin-left: 10px;"></i>
442
  <div>
443
  <p style="font-weight: 600; margin-bottom: 5px;" id="fileName"></p>
444
  <p style="color: #666; font-size: 14px;" id="fileSize"></p>
445
+ <p style="color: #666; font-size: 14px;" id="studentCount"></p>
446
  </div>
447
  <button id="clearFileBtn" style="background: none; border: none; margin-right: auto; color: var(--error-color); cursor: pointer;">
448
  <i class="fas fa-times"></i>
 
472
  <div class="preview-section">
473
  <div class="preview-header">
474
  <h3><i class="fas fa-eye"></i> معاينة الرسائل</h3>
475
+ <span id="previewCount" style="font-size: 14px; color: #666;"></span>
476
  </div>
477
  <div class="preview-content">
478
  <p id="previewMessage">سيتم عرض معاينة الرسائل هنا بعد تحميل الملف وإدخال نموذج الرسالة.</p>
 
485
  <button class="btn send-btn" id="sendMessagesBtn" disabled>
486
  <i class="fab fa-whatsapp"></i> إرسال الرسائل
487
  </button>
488
+ <p id="sendInfo" style="margin-top: 10px; font-size: 14px; color: #666;"></p>
489
  </section>
490
  </div>
491
  </div>
 
507
  </div>
508
  </div>
509
 
510
+ <div id="successCount" style="text-align: center; margin: 10px 0; color: var(--success-color);"></div>
511
+ <div id="errorCount" style="text-align: center; margin: 10px 0; color: var(--error-color);"></div>
512
+
513
  <div style="text-align: center;">
514
  <button class="btn btn-secondary" id="cancelSendingBtn">
515
  <i class="fas fa-stop"></i> إلغاء العملية
 
528
 
529
  <div style="margin: 20px 0; text-align: center;">
530
  <p id="successMessage"></p>
531
+ <div id="finalStats" style="margin-top: 15px;"></div>
532
  </div>
533
 
534
  <div style="text-align: center;">
535
  <button class="btn" id="okSuccessBtn">
536
  <i class="fas fa-check"></i> حسناً
537
  </button>
538
+ <button class="btn btn-secondary" id="downloadReportBtn" style="margin-right: 10px;">
539
+ <i class="fas fa-download"></i> تنزيل التقرير
540
+ </button>
541
+ </div>
542
+ </div>
543
+ </div>
544
+
545
+ <!-- Error Modal -->
546
+ <div class="modal" id="errorModal">
547
+ <div class="modal-content">
548
+ <div style="text-align: center; margin: 20px 0;">
549
+ <i class="fas fa-exclamation-circle" style="font-size: 60px; color: var(--error-color);"></i>
550
+ <h3 style="margin-top: 15px;" id="errorModalTitle">حدث خطأ أثناء معالجة الملف</h3>
551
+ </div>
552
+
553
+ <div style="margin: 20px 0; text-align: center;">
554
+ <p id="errorModalMessage"></p>
555
+ </div>
556
+
557
+ <div style="text-align: center;">
558
+ <button class="btn" id="okErrorBtn">
559
+ <i class="fas fa-check"></i> حسناً
560
+ </button>
561
  </div>
562
  </div>
563
  </div>
 
571
  const fileInfo = document.getElementById('fileInfo');
572
  const fileName = document.getElementById('fileName');
573
  const fileSize = document.getElementById('fileSize');
574
+ const studentCount = document.getElementById('studentCount');
575
  const clearFileBtn = document.getElementById('clearFileBtn');
576
  const messageTemplate = document.getElementById('messageTemplate');
577
  const customLink = document.getElementById('customLink');
578
  const previewMessage = document.getElementById('previewMessage');
579
+ const previewCount = document.getElementById('previewCount');
580
  const studentList = document.getElementById('studentList');
581
  const sendMessagesBtn = document.getElementById('sendMessagesBtn');
582
+ const sendInfo = document.getElementById('sendInfo');
583
  const progressModal = document.getElementById('progressModal');
584
  const progressBar = document.getElementById('progressBar');
585
  const statusMessage = document.getElementById('statusMessage');
586
+ const successCount = document.getElementById('successCount');
587
+ const errorCount = document.getElementById('errorCount');
588
  const closeModalBtn = document.getElementById('closeModalBtn');
589
  const cancelSendingBtn = document.getElementById('cancelSendingBtn');
590
  const successModal = document.getElementById('successModal');
591
  const successMessage = document.getElementById('successMessage');
592
+ const finalStats = document.getElementById('finalStats');
593
  const okSuccessBtn = document.getElementById('okSuccessBtn');
594
+ const downloadReportBtn = document.getElementById('downloadReportBtn');
595
+ const errorModal = document.getElementById('errorModal');
596
+ const errorModalTitle = document.getElementById('errorModalTitle');
597
+ const errorModalMessage = document.getElementById('errorModalMessage');
598
+ const okErrorBtn = document.getElementById('okErrorBtn');
599
+ const downloadSampleLink = document.getElementById('downloadSample');
600
 
601
  // Variables
602
  let studentsData = [];
603
  let sendingProcess = null;
604
+ let successCounter = 0;
605
+ let errorCounter = 0;
606
 
607
  // Event Listeners
608
  selectFileBtn.addEventListener('click', function() {
 
611
 
612
  uploadContainer.addEventListener('dragover', function(e) {
613
  e.preventDefault();
614
+ uploadContainer.classList.add('active');
 
615
  });
616
 
617
  uploadContainer.addEventListener('dragleave', function() {
618
+ uploadContainer.classList.remove('active');
 
619
  });
620
 
621
  uploadContainer.addEventListener('drop', function(e) {
622
  e.preventDefault();
623
+ uploadContainer.classList.remove('active');
 
624
 
625
  if (e.dataTransfer.files.length) {
626
  fileInput.files = e.dataTransfer.files;
 
631
  fileInput.addEventListener('change', handleFileUpload);
632
 
633
  clearFileBtn.addEventListener('click', function() {
634
+ resetFileUpload();
 
 
 
 
635
  });
636
 
637
  messageTemplate.addEventListener('input', function() {
638
  updatePreview();
639
+ updateSendButtonState();
640
  });
641
 
642
  customLink.addEventListener('input', function() {
 
652
  cancelSendingBtn.addEventListener('click', function() {
653
  if (sendingProcess) {
654
  clearInterval(sendingProcess);
655
+ sendingProcess = null;
656
+ statusMessage.innerHTML = '<span class="warning">تم إيقاف عملية الإرسال</span>';
657
  cancelSendingBtn.disabled = true;
658
+
659
+ // Show final stats
660
+ showFinalStats();
661
  }
662
  });
663
 
 
665
  successModal.style.display = 'none';
666
  });
667
 
668
+ okErrorBtn.addEventListener('click', function() {
669
+ errorModal.style.display = 'none';
670
+ });
671
+
672
+ downloadReportBtn.addEventListener('click', function() {
673
+ downloadReport();
674
+ });
675
+
676
+ downloadSampleLink.addEventListener('click', function(e) {
677
+ e.preventDefault();
678
+ downloadSampleFile();
679
+ });
680
+
681
  // Add event listeners for template tags
682
  document.querySelectorAll('.tag').forEach(tag => {
683
  tag.addEventListener('click', function() {
 
692
  const file = fileInput.files[0];
693
  if (!file) return;
694
 
695
+ // Check file type
696
+ const validTypes = ['application/vnd.ms-excel',
697
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
698
+ 'text/csv'];
699
+ if (!validTypes.includes(file.type) &&
700
+ !file.name.endsWith('.xls') &&
701
+ !file.name.endsWith('.xlsx') &&
702
+ !file.name.endsWith('.csv')) {
703
+ showError('نوع ملف غير مدعوم', 'الرجاء تحميل ملف Excel (xls, xlsx) أو ملف CSV.');
704
+ resetFileUpload();
705
+ return;
706
+ }
707
+
708
+ // Show loading state
709
+ uploadContainer.classList.add('active');
710
+ selectFileBtn.innerHTML = '<span class="spinner"></span> جاري معالجة الملف...';
711
+ selectFileBtn.disabled = true;
712
+
713
+ const reader = new FileReader();
714
+
715
+ reader.onload = function(e) {
716
+ try {
717
+ const data = new Uint8Array(e.target.result);
718
+ const workbook = XLSX.read(data, { type: 'array' });
719
+
720
+ // Get first sheet
721
+ const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
722
+
723
+ // Convert to JSON
724
+ const jsonData = XLSX.utils.sheet_to_json(firstSheet);
725
+
726
+ if (jsonData.length === 0) {
727
+ showError('ملف فارغ', 'الملف الذي تم تحميله لا يحتوي على أي بيانات.');
728
+ resetFileUpload();
729
+ return;
730
+ }
731
+
732
+ // Process data and look for required columns
733
+ let nameKey = findColumnKey(jsonData[0], ['اسم', 'اسم الطالب', 'الاسم', 'الطالب', 'name', 'student']);
734
+ let phoneKey = findColumnKey(jsonData[0], ['رقم الجوال', 'الهاتف', 'رقم الهاتف', 'phone', 'mobile', 'whatsapp']);
735
+
736
+ if (!nameKey || !phoneKey) {
737
+ showError('تنسيق ملف غير صحيح', 'الملف يجب أن يحتوي على أعمدة لكل من الاسم ورقم الجوال.');
738
+ resetFileUpload();
739
+ return;
740
+ }
741
+
742
+ studentsData = jsonData.map(row => {
743
+ return {
744
+ name: row[nameKey] || 'غير معروف',
745
+ phone: sanitizePhoneNumber(row[phoneKey])
746
+ };
747
+ }).filter(student => student.phone); // Filter out invalid phone numbers
748
+
749
+ if (studentsData.length === 0) {
750
+ showError('بيانات غير صالحة', 'لم يتم العثور على أرقام هواتف صالحة في الملف.');
751
+ resetFileUpload();
752
+ return;
753
+ }
754
+
755
+ // Show file info
756
+ fileName.textContent = file.name;
757
+ fileSize.textContent = formatFileSize(file.size);
758
+ studentCount.textContent = `عدد الطلاب: ${studentsData.length}`;
759
+ fileInfo.style.display = 'block';
760
+
761
+ // Update UI
762
+ uploadContainer.classList.remove('active');
763
+ selectFileBtn.innerHTML = '<i class="fas fa-folder-open"></i> اختر ملف';
764
+ selectFileBtn.disabled = false;
765
+
766
+ updatePreview();
767
+ updateSendButtonState();
768
+ updateSendInfo();
769
+
770
+ } catch (error) {
771
+ console.error('Error processing file:', error);
772
+ showError('خطأ في معالجة الملف', 'حدث خطأ أثناء قراءة الملف. الرجاء التحقق من صحة الملف وحاول مرة أخرى.');
773
+ resetFileUpload();
774
+ }
775
+ };
776
+
777
+ reader.onerror = function() {
778
+ showError('خطأ في قراءة الملف', 'تعذر قراءة الملف. الرجاء المحاولة مرة أخرى.');
779
+ resetFileUpload();
780
+ };
781
+
782
+ reader.readAsArrayBuffer(file);
783
  }
784
 
785
+ function findColumnKey(row, possibleKeys) {
786
+ const existingKeys = Object.keys(row);
787
+ for (let key of possibleKeys) {
788
+ if (existingKeys.includes(key)) {
789
+ return key;
790
+ }
791
+ }
792
+ return null;
793
+ }
794
+
795
+ function sanitizePhoneNumber(phone) {
796
+ if (!phone) return null;
797
+
798
+ // Convert to string if it's a number
799
+ phone = phone.toString();
800
 
801
+ // Remove all non-digit characters
802
+ phone = phone.replace(/\D/g, '');
803
+
804
+ // Saudi number validation (966 + 9 digits)
805
+ if (phone.startsWith('966') && phone.length === 12) {
806
+ return phone;
807
  }
808
 
809
+ // International format
810
+ if (phone.length >= 10 && phone.length <= 15) {
811
+ return phone;
812
+ }
813
+
814
+ return null;
815
  }
816
 
817
  function formatFileSize(bytes) {
818
+ if (bytes === 0) return '0 بايت';
819
  const k = 1024;
820
+ const sizes = ['بايت', 'كيلوبايت', 'ميجابايت', 'جيجابايت'];
821
  const i = Math.floor(Math.log(bytes) / Math.log(k));
822
  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
823
  }
824
 
825
+ function resetFileUpload() {
826
+ fileInput.value = '';
827
+ fileInfo.style.display = 'none';
828
+ studentsData = [];
829
+ uploadContainer.classList.remove('active', 'error');
830
+ selectFileBtn.innerHTML = '<i class="fas fa-folder-open"></i> اختر ملف';
831
+ selectFileBtn.disabled = false;
832
+ updatePreview();
833
+ updateSendButtonState();
834
+ updateSendInfo();
835
+ }
836
+
837
  function updatePreview() {
838
  if (studentsData.length === 0) {
839
  studentList.style.display = 'none';
840
  previewMessage.style.display = 'block';
841
  previewMessage.textContent = 'سيتم عرض معاينة الرسائل هنا بعد تحميل الملف وإدخال نموذج الرسالة.';
842
+ previewCount.textContent = '';
843
  return;
844
  }
845
 
 
848
  studentList.style.display = 'none';
849
  previewMessage.style.display = 'block';
850
  previewMessage.textContent = 'الرجاء إدخال نموذج الرسالة لمعاينة الرسائل.';
851
+ previewCount.textContent = '';
852
  return;
853
  }
854
 
855
  studentList.innerHTML = '';
856
  previewMessage.style.display = 'none';
857
  studentList.style.display = 'block';
858
+ previewCount.textContent = `عرض ${Math.min(5, studentsData.length)} من ${studentsData.length}`;
859
 
860
+ // Show preview for first 5 students
861
+ const previewCountNum = Math.min(5, studentsData.length);
862
+ for (let i = 0; i < previewCountNum; i++) {
863
  const student = studentsData[i];
864
  const link = customLink.value || '{الرابط}';
865
  const processedMessage = processMessage(message, student.name, link);
 
869
  li.innerHTML = `
870
  <div style="flex: 1;">
871
  <strong>${student.name}</strong>
872
+ <div style="font-size: 12px; color: #666; margin-top: 4px;">${formatPhoneNumber(student.phone)}</div>
873
  </div>
874
  <div style="max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
875
  ${processedMessage}
 
878
  studentList.appendChild(li);
879
  }
880
 
881
+ if (studentsData.length > 5) {
882
  const li = document.createElement('li');
883
  li.className = 'student-item';
884
  li.style.textAlign = 'center';
885
  li.style.color = '#666';
886
+ li.textContent = `و ${studentsData.length - 5} طلاب آخرين...`;
887
  studentList.appendChild(li);
888
  }
889
  }
890
 
891
+ function formatPhoneNumber(phone) {
892
+ // Format Saudi numbers
893
+ if (phone.startsWith('966')) {
894
+ return `+${phone.substring(0, 3)} ${phone.substring(3, 5)} ${phone.substring(5, 8)} ${phone.substring(8)}`;
895
+ }
896
+ return `+${phone}`;
897
+ }
898
+
899
  function processMessage(template, name, link) {
900
  const today = new Date();
901
  const dateStr = `${today.getDate()}/${today.getMonth() + 1}/${today.getFullYear()}`;
 
903
  return template
904
  .replace(/{اسم الطالب}/g, name)
905
  .replace(/{الرابط}/g, link)
906
+ .replace(/{الرقم}/g, '+966XXXXXXXXX')
907
  .replace(/{التاريخ}/g, dateStr);
908
  }
909
 
 
911
  sendMessagesBtn.disabled = studentsData.length === 0 || !messageTemplate.value;
912
  }
913
 
914
+ function updateSendInfo() {
915
+ if (studentsData.length > 0) {
916
+ sendInfo.textContent = `جاهز لإرسال ${studentsData.length} رسالة`;
917
+ } else {
918
+ sendInfo.textContent = '';
919
+ }
920
+ }
921
+
922
  function insertAtCursor(textarea, text) {
923
  const startPos = textarea.selectionStart;
924
  const endPos = textarea.selectionEnd;
 
936
  }
937
 
938
  function startSendingProcess() {
939
+ if (studentsData.length === 0 || !messageTemplate.value) return;
940
+
941
+ // Reset counters
942
+ successCounter = 0;
943
+ errorCounter = 0;
944
+
945
+ // Show progress modal
946
  progressModal.style.display = 'flex';
947
  progressBar.style.width = '0%';
948
+ successCount.textContent = '';
949
+ errorCount.textContent = '';
950
  cancelSendingBtn.disabled = false;
951
 
 
952
  const totalStudents = studentsData.length;
953
  const link = customLink.value || '{الرابط}';
954
+ let currentIndex = 0;
955
 
956
  sendingProcess = setInterval(() => {
957
+ if (currentIndex >= totalStudents) {
958
+ // Finished sending
959
  clearInterval(sendingProcess);
960
  sendingProcess = null;
961
 
962
  // Show success message
963
  progressModal.style.display = 'none';
964
+
965
+ if (errorCounter === 0) {
966
+ successMessage.textContent = `تم إرسال جميع الرسائل بنجاح إلى ${totalStudents} طالب!`;
967
+ } else {
968
+ successMessage.textContent = `تم إرسال ${successCounter} رسالة بنجاح من أصل ${totalStudents}.`;
969
+ }
970
+
971
+ showFinalStats();
972
  successModal.style.display = 'flex';
973
  return;
974
  }
975
 
976
+ const student = studentsData[currentIndex];
977
+ const message = processMessage(messageTemplate.value, student.name, link);
 
 
 
 
 
978
 
979
+ // Update progress
980
+ const percent = Math.round(((currentIndex + 1) / totalStudents) * 100);
981
+ progressBar.style.width = `${percent}%`;
982
+ statusMessage.innerHTML = `جاري إرسال الرسالة إلى <strong>${student.name}</strong> (${currentIndex + 1}/${totalStudents})...`;
983
 
984
+ // Simulate sending (in a real app, you would call WhatsApp API)
985
+ setTimeout(() => {
986
+ // Randomly simulate failures (for demo purposes)
987
+ if (Math.random() < 0.1) {
988
+ errorCounter++;
989
+ errorCount.textContent = `رسائل غير مرسلة: ${errorCounter}`;
990
+
991
+ // Retry logic (for demo, just continue)
992
+ if (Math.random() < 0.5 && currentIndex < totalStudents) {
993
+ statusMessage.innerHTML = `<span class="error">فشل إرسال الرسالة إلى ${student.name} - جاري إعادة المحاولة...</span>`;
994
+ currentIndex--;
995
+ } else {
996
+ statusMessage.innerHTML = `<span class="error">فشل إرسال الرسالة إلى ${student.name} - سيتم تخطي هذا الطالب</span>`;
997
+ }
998
+ } else {
999
+ successCounter++;
1000
+ successCount.textContent = `رسائل مرسلة: ${successCounter}`;
1001
+ }
1002
+
1003
+ currentIndex++;
1004
+ }, 1000);
1005
  }, 1500);
1006
  }
1007
 
1008
+ function showFinalStats() {
1009
+ const total = successCounter + errorCounter;
1010
+ finalStats.innerHTML = `
1011
+ <div style="display: flex; justify-content: space-around; margin-top: 10px;">
1012
+ <div>
1013
+ <div style="font-size: 24px; color: var(--success-color);">${successCounter}</div>
1014
+ <div style="font-size: 14px;">ناجحة</div>
1015
+ </div>
1016
+ <div>
1017
+ <div style="font-size: 24px; color: var(--error-color);">${errorCounter}</div>
1018
+ <div style="font-size: 14px;">فاشلة</div>
1019
+ </div>
1020
+ <div>
1021
+ <div style="font-size: 24px; color: var(--secondary-color);">${total}</div>
1022
+ <div style="font-size: 14px;">المجموع</div>
1023
+ </div>
1024
+ </div>
1025
+ `;
1026
+ }
1027
+
1028
+ function downloadReport() {
1029
+ // Create a CSV report
1030
+ let csvContent = "اسم الطالب,رقم الجوال,الحالة\n";
1031
+
1032
+ studentsData.forEach((student, index) => {
1033
+ const status = index < successCounter ? "ناجح" : "فشل";
1034
+ csvContent += `${student.name},${formatPhoneNumber(student.phone)},${status}\n`;
1035
+ });
1036
+
1037
+ // Create download link
1038
+ const blob = new Blob(["\uFEFF"+csvContent], { type: 'text/csv;charset=utf-8;' });
1039
+ const url = URL.createObjectURL(blob);
1040
+ const link = document.createElement('a');
1041
+ link.setAttribute('href', url);
1042
+ link.setAttribute('download', `تقرير_إرسال_الرسائل_${new Date().toLocaleDateString('ar')}.csv`);
1043
+ document.body.appendChild(link);
1044
+ link.click();
1045
+ document.body.removeChild(link);
1046
+ }
1047
+
1048
+ function downloadSampleFile() {
1049
+ // Create sample Excel file data
1050
+ const sampleData = [
1051
+ ['اسم الطالب', 'رقم الجوال', 'البريد الإلكتروني'],
1052
+ ['أحمد محمد', '966501234567', '[email protected]'],
1053
+ ['فاطمة علي', '966502345678', '[email protected]'],
1054
+ ['محمد حسن', '966503456789', '[email protected]']
1055
+ ];
1056
+
1057
+ // Create workbook
1058
+ const wb = XLSX.utils.book_new();
1059
+ const ws = XLSX.utils.aoa_to_sheet(sampleData);
1060
+ XLSX.utils.book_append_sheet(wb, ws, "الطلاب");
1061
+
1062
+ // Generate and download
1063
+ XLSX.writeFile(wb, 'نموذج_قائمة_الطلاب.xlsx');
1064
+ }
1065
+
1066
+ function showError(title, message) {
1067
+ uploadContainer.classList.add('error');
1068
+ errorModalTitle.textContent = title;
1069
+ errorModalMessage.textContent = message;
1070
+ errorModal.style.display = 'flex';
1071
+ }
1072
+
1073
  // Handle clicks outside modal to close it
1074
  window.addEventListener('click', function(event) {
1075
  if (event.target === progressModal) {
 
1078
  if (event.target === successModal) {
1079
  successModal.style.display = 'none';
1080
  }
1081
+ if (event.target === errorModal) {
1082
+ errorModal.style.display = 'none';
1083
+ }
1084
  });
1085
  });
1086
  </script>
1087
+ </body>
1088
  </html>