api-whats-app / index.html
melassy's picture
Add 1 files
cdeebf8 verified
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>نظام إرسال رسائل الواتساب للطلاب</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<style>
:root {
--primary-color: #25D366;
--secondary-color: #128C7E;
--accent-color: #34B7F1;
--text-color: #333;
--light-bg: #f5f5f5;
--white: #ffffff;
--error-color: #ff4444;
--success-color: #00C851;
--warning-color: #ffbb33;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--light-bg);
color: var(--text-color);
line-height: 1.6;
}
.container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
}
header {
background-color: var(--secondary-color);
color: var(--white);
padding: 20px 0;
text-align: center;
border-radius: 10px 10px 0 0;
margin-bottom: 30px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
header h1 {
font-size: 28px;
margin-bottom: 10px;
}
header p {
font-size: 16px;
opacity: 0.9;
}
.app-logo {
font-size: 40px;
margin-bottom: 15px;
color: var(--white);
}
.main-container {
background-color: var(--white);
border-radius: 10px;
padding: 30px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.upload-section {
margin-bottom: 30px;
border-bottom: 1px solid #eee;
padding-bottom: 30px;
}
.upload-container {
border: 2px dashed #ccc;
padding: 30px;
text-align: center;
border-radius: 8px;
transition: all 0.3s;
background-color: var(--light-bg);
position: relative;
}
.upload-container:hover {
border-color: var(--accent-color);
background-color: rgba(52, 183, 241, 0.05);
}
.upload-container.active {
border-color: var(--primary-color);
background-color: rgba(37, 211, 102, 0.05);
}
.upload-container.error {
border-color: var(--error-color);
background-color: rgba(255, 68, 68, 0.05);
}
.upload-container i {
font-size: 48px;
color: var(--accent-color);
margin-bottom: 15px;
}
.upload-container p {
margin-bottom: 20px;
color: #666;
}
.btn {
background-color: var(--primary-color);
color: var(--white);
border: none;
padding: 12px 25px;
border-radius: 50px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
transition: all 0.3s;
display: inline-flex;
align-items: center;
justify-content: center;
}
.btn:hover {
background-color: var(--secondary-color);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.btn i {
margin-left: 8px;
}
.btn-secondary {
background-color: #6c757d;
}
.btn-secondary:hover {
background-color: #5a6268;
}
.form-group {
margin-bottom: 25px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: var(--text-color);
}
.form-control {
width: 100%;
padding: 12px 15px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 16px;
transition: border 0.3s;
}
.form-control:focus {
border-color: var(--accent-color);
outline: none;
box-shadow: 0 0 0 3px rgba(52, 183, 241, 0.2);
}
textarea.form-control {
min-height: 120px;
resize: vertical;
}
.preview-section {
background-color: var(--light-bg);
padding: 20px;
border-radius: 8px;
margin-top: 30px;
border: 1px solid #eee;
}
.preview-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.preview-content {
background-color: var(--white);
padding: 15px;
border-radius: 8px;
border: 1px solid #ddd;
max-height: 300px;
overflow-y: auto;
}
.student-list {
list-style: none;
}
.student-item {
padding: 12px 15px;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
}
.student-item:last-child {
border-bottom: none;
}
.send-section {
margin-top: 40px;
text-align: center;
}
.send-btn {
padding: 15px 40px;
font-size: 18px;
}
/* File Requirements Info */
.file-requirements {
background-color: rgba(52, 183, 241, 0.1);
border-left: 4px solid var(--accent-color);
padding: 12px 15px;
margin-top: 15px;
border-radius: 4px;
font-size: 14px;
}
.file-requirements h4 {
margin-bottom: 8px;
color: var(--secondary-color);
}
.file-requirements ul {
list-style-position: inside;
padding-right: 10px;
}
.file-requirements li {
margin-bottom: 5px;
}
/* Loading Animation */
.spinner {
width: 24px;
height: 24px;
border: 3px solid rgba(255,255,255,0.3);
border-radius: 50%;
border-top-color: var(--white);
animation: spin 1s ease-in-out infinite;
display: inline-block;
vertical-align: middle;
margin-left: 8px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Modals */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background-color: var(--white);
padding: 30px;
border-radius: 10px;
width: 90%;
max-width: 500px;
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.modal-title {
font-size: 20px;
font-weight: 600;
}
.close-modal {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
}
.progress-container {
margin: 20px 0;
}
.progress-bar {
height: 10px;
background-color: #eee;
border-radius: 5px;
overflow: hidden;
}
.progress {
height: 100%;
background-color: var(--primary-color);
width: 0;
transition: width 0.3s;
}
.status-message {
text-align: center;
margin: 15px 0;
font-size: 14px;
color: #666;
}
.error {
color: var(--error-color);
}
.success {
color: var(--success-color);
}
.warning {
color: var(--warning-color);
}
.template-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 10px;
}
.tag {
background-color: var(--light-bg);
padding: 5px 10px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
border: 1px solid #ddd;
transition: all 0.2s;
}
.tag:hover {
background-color: var(--accent-color);
color: var(--white);
}
/* Responsive */
@media (max-width: 768px) {
.container {
padding: 15px;
}
.main-container {
padding: 20px;
}
.upload-container {
padding: 20px 15px;
}
.btn {
padding: 10px 20px;
font-size: 14px;
}
.student-item {
flex-direction: column;
align-items: flex-start;
}
.student-item div:nth-child(2) {
margin-top: 8px;
max-width: 100%;
}
}
</style>
</head>
<body>
<header>
<div class="container">
<div class="app-logo">
<i class="fab fa-whatsapp"></i>
</div>
<h1>نظام إرسال رسائل الواتساب للطلاب</h1>
<p>أرسل رسائل مخصصة للطلاب بسهولة وبشكل آلي</p>
</div>
</header>
<div class="container">
<div class="main-container">
<section class="upload-section">
<h2><i class="fas fa-file-upload"></i> تحميل ملف الطلاب</h2>
<div class="upload-container" id="uploadContainer">
<i class="fas fa-file-excel"></i>
<p>قم بسحب وإسقاط ملف Excel هنا أو انقر لاختيار الملف</p>
<input type="file" id="fileInput" accept=".xlsx,.xls,.csv" style="display: none;">
<button class="btn" id="selectFileBtn">
<i class="fas fa-folder-open"></i> اختر ملف
</button>
</div>
<div class="file-requirements">
<h4><i class="fas fa-info-circle"></i> متطلبات الملف:</h4>
<ul>
<li>يجب أن يكون الملف من نوع Excel (xlsx, xls) أو CSV</li>
<li>يجب أن يحتوي على عمود باسم "الاسم" أو "اسم الطالب"</li>
<li>يجب أن يحتوي على عمود باسم "رقم الجوال" أو "الهاتف"</li>
<li>يمكنك <a href="#" id="downloadSample">تحميل نموذج</a> لاستخدامه كمرجع</li>
</ul>
</div>
<div id="fileInfo" style="margin-top: 15px; display: none;">
<div class="file-details" style="display: flex; align-items: center;">
<i class="fas fa-file-excel" style="color: var(--success-color); font-size: 24px; margin-left: 10px;"></i>
<div>
<p style="font-weight: 600; margin-bottom: 5px;" id="fileName"></p>
<p style="color: #666; font-size: 14px;" id="fileSize"></p>
<p style="color: #666; font-size: 14px;" id="studentCount"></p>
</div>
<button id="clearFileBtn" style="background: none; border: none; margin-right: auto; color: var(--error-color); cursor: pointer;">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</section>
<section class="message-section">
<h2><i class="fas fa-comment-alt"></i> تكوين الرسالة</h2>
<div class="form-group">
<label for="messageTemplate">نموذج الرسالة</label>
<textarea id="messageTemplate" class="form-control" placeholder="عزيزي {اسم الطالب}، نود إعلامك بأن... الرابط: {الرابط}"></textarea>
<div class="template-tags">
<span class="tag" data-tag="{اسم الطالب}">{اسم الطالب}</span>
<span class="tag" data-tag="{الرابط}">{الرابط}</span>
<span class="tag" data-tag="{الرقم}">{الرقم}</span>
<span class="tag" data-tag="{التاريخ}">{التاريخ}</span>
</div>
</div>
<div class="form-group">
<label for="customLink">رابط مخصص (اختياري)</label>
<input type="url" id="customLink" class="form-control" placeholder="https://example.com">
</div>
<div class="preview-section">
<div class="preview-header">
<h3><i class="fas fa-eye"></i> معاينة الرسائل</h3>
<span id="previewCount" style="font-size: 14px; color: #666;"></span>
</div>
<div class="preview-content">
<p id="previewMessage">سيتم عرض معاينة الرسائل هنا بعد تحميل الملف وإدخال نموذج الرسالة.</p>
<ul class="student-list" id="studentList" style="display: none;"></ul>
</div>
</div>
</section>
<section class="send-section">
<button class="btn send-btn" id="sendMessagesBtn" disabled>
<i class="fab fa-whatsapp"></i> إرسال الرسائل
</button>
<p id="sendInfo" style="margin-top: 10px; font-size: 14px; color: #666;"></p>
</section>
</div>
</div>
<!-- Progress Modal -->
<div class="modal" id="progressModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title"><i class="fas fa-paper-plane"></i> جارٍ إرسال الرسائل</h3>
<button class="close-modal" id="closeModalBtn">&times;</button>
</div>
<div class="progress-container">
<div class="progress-bar">
<div class="progress" id="progressBar"></div>
</div>
<div class="status-message" id="statusMessage">
جاهز للبدء...
</div>
</div>
<div id="successCount" style="text-align: center; margin: 10px 0; color: var(--success-color);"></div>
<div id="errorCount" style="text-align: center; margin: 10px 0; color: var(--error-color);"></div>
<div style="text-align: center;">
<button class="btn btn-secondary" id="cancelSendingBtn">
<i class="fas fa-stop"></i> إلغاء العملية
</button>
</div>
</div>
</div>
<!-- Success Modal -->
<div class="modal" id="successModal">
<div class="modal-content">
<div style="text-align: center; margin: 20px 0;">
<i class="fas fa-check-circle" style="font-size: 60px; color: var(--success-color);"></i>
<h3 style="margin-top: 15px;">تم إرسال الرسائل بنجاح!</h3>
</div>
<div style="margin: 20px 0; text-align: center;">
<p id="successMessage"></p>
<div id="finalStats" style="margin-top: 15px;"></div>
</div>
<div style="text-align: center;">
<button class="btn" id="okSuccessBtn">
<i class="fas fa-check"></i> حسناً
</button>
<button class="btn btn-secondary" id="downloadReportBtn" style="margin-right: 10px;">
<i class="fas fa-download"></i> تنزيل التقرير
</button>
</div>
</div>
</div>
<!-- Error Modal -->
<div class="modal" id="errorModal">
<div class="modal-content">
<div style="text-align: center; margin: 20px 0;">
<i class="fas fa-exclamation-circle" style="font-size: 60px; color: var(--error-color);"></i>
<h3 style="margin-top: 15px;" id="errorModalTitle">حدث خطأ أثناء معالجة الملف</h3>
</div>
<div style="margin: 20px 0; text-align: center;">
<p id="errorModalMessage"></p>
</div>
<div style="text-align: center;">
<button class="btn" id="okErrorBtn">
<i class="fas fa-check"></i> حسناً
</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const uploadContainer = document.getElementById('uploadContainer');
const fileInput = document.getElementById('fileInput');
const selectFileBtn = document.getElementById('selectFileBtn');
const fileInfo = document.getElementById('fileInfo');
const fileName = document.getElementById('fileName');
const fileSize = document.getElementById('fileSize');
const studentCount = document.getElementById('studentCount');
const clearFileBtn = document.getElementById('clearFileBtn');
const messageTemplate = document.getElementById('messageTemplate');
const customLink = document.getElementById('customLink');
const previewMessage = document.getElementById('previewMessage');
const previewCount = document.getElementById('previewCount');
const studentList = document.getElementById('studentList');
const sendMessagesBtn = document.getElementById('sendMessagesBtn');
const sendInfo = document.getElementById('sendInfo');
const progressModal = document.getElementById('progressModal');
const progressBar = document.getElementById('progressBar');
const statusMessage = document.getElementById('statusMessage');
const successCount = document.getElementById('successCount');
const errorCount = document.getElementById('errorCount');
const closeModalBtn = document.getElementById('closeModalBtn');
const cancelSendingBtn = document.getElementById('cancelSendingBtn');
const successModal = document.getElementById('successModal');
const successMessage = document.getElementById('successMessage');
const finalStats = document.getElementById('finalStats');
const okSuccessBtn = document.getElementById('okSuccessBtn');
const downloadReportBtn = document.getElementById('downloadReportBtn');
const errorModal = document.getElementById('errorModal');
const errorModalTitle = document.getElementById('errorModalTitle');
const errorModalMessage = document.getElementById('errorModalMessage');
const okErrorBtn = document.getElementById('okErrorBtn');
const downloadSampleLink = document.getElementById('downloadSample');
// Variables
let studentsData = [];
let sendingProcess = null;
let successCounter = 0;
let errorCounter = 0;
// Event Listeners
selectFileBtn.addEventListener('click', function() {
fileInput.click();
});
uploadContainer.addEventListener('dragover', function(e) {
e.preventDefault();
uploadContainer.classList.add('active');
});
uploadContainer.addEventListener('dragleave', function() {
uploadContainer.classList.remove('active');
});
uploadContainer.addEventListener('drop', function(e) {
e.preventDefault();
uploadContainer.classList.remove('active');
if (e.dataTransfer.files.length) {
fileInput.files = e.dataTransfer.files;
handleFileUpload();
}
});
fileInput.addEventListener('change', handleFileUpload);
clearFileBtn.addEventListener('click', function() {
resetFileUpload();
});
messageTemplate.addEventListener('input', function() {
updatePreview();
updateSendButtonState();
});
customLink.addEventListener('input', function() {
updatePreview();
});
sendMessagesBtn.addEventListener('click', startSendingProcess);
closeModalBtn.addEventListener('click', function() {
progressModal.style.display = 'none';
});
cancelSendingBtn.addEventListener('click', function() {
if (sendingProcess) {
clearInterval(sendingProcess);
sendingProcess = null;
statusMessage.innerHTML = '<span class="warning">تم إيقاف عملية الإرسال</span>';
cancelSendingBtn.disabled = true;
// Show final stats
showFinalStats();
}
});
okSuccessBtn.addEventListener('click', function() {
successModal.style.display = 'none';
});
okErrorBtn.addEventListener('click', function() {
errorModal.style.display = 'none';
});
downloadReportBtn.addEventListener('click', function() {
downloadReport();
});
downloadSampleLink.addEventListener('click', function(e) {
e.preventDefault();
downloadSampleFile();
});
// Add event listeners for template tags
document.querySelectorAll('.tag').forEach(tag => {
tag.addEventListener('click', function() {
const tagValue = this.getAttribute('data-tag');
insertAtCursor(messageTemplate, tagValue);
messageTemplate.focus();
});
});
// Functions
function handleFileUpload() {
const file = fileInput.files[0];
if (!file) return;
// Check file type
const validTypes = ['application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'text/csv'];
if (!validTypes.includes(file.type) &&
!file.name.endsWith('.xls') &&
!file.name.endsWith('.xlsx') &&
!file.name.endsWith('.csv')) {
showError('نوع ملف غير مدعوم', 'الرجاء تحميل ملف Excel (xls, xlsx) أو ملف CSV.');
resetFileUpload();
return;
}
// Show loading state
uploadContainer.classList.add('active');
selectFileBtn.innerHTML = '<span class="spinner"></span> جاري معالجة الملف...';
selectFileBtn.disabled = true;
const reader = new FileReader();
reader.onload = function(e) {
try {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
// Get first sheet
const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
// Convert to JSON
const jsonData = XLSX.utils.sheet_to_json(firstSheet);
if (jsonData.length === 0) {
showError('ملف فارغ', 'الملف الذي تم تحميله لا يحتوي على أي بيانات.');
resetFileUpload();
return;
}
// Process data and look for required columns
let nameKey = findColumnKey(jsonData[0], ['اسم', 'اسم الطالب', 'الاسم', 'الطالب', 'name', 'student']);
let phoneKey = findColumnKey(jsonData[0], ['رقم الجوال', 'الهاتف', 'رقم الهاتف', 'phone', 'mobile', 'whatsapp']);
if (!nameKey || !phoneKey) {
showError('تنسيق ملف غير صحيح', 'الملف يجب أن يحتوي على أعمدة لكل من الاسم ورقم الجوال.');
resetFileUpload();
return;
}
studentsData = jsonData.map(row => {
return {
name: row[nameKey] || 'غير معروف',
phone: sanitizePhoneNumber(row[phoneKey])
};
}).filter(student => student.phone); // Filter out invalid phone numbers
if (studentsData.length === 0) {
showError('بيانات غير صالحة', 'لم يتم العثور على أرقام هواتف صالحة في الملف.');
resetFileUpload();
return;
}
// Show file info
fileName.textContent = file.name;
fileSize.textContent = formatFileSize(file.size);
studentCount.textContent = `عدد الطلاب: ${studentsData.length}`;
fileInfo.style.display = 'block';
// Update UI
uploadContainer.classList.remove('active');
selectFileBtn.innerHTML = '<i class="fas fa-folder-open"></i> اختر ملف';
selectFileBtn.disabled = false;
updatePreview();
updateSendButtonState();
updateSendInfo();
} catch (error) {
console.error('Error processing file:', error);
showError('خطأ في معالجة الملف', 'حدث خطأ أثناء قراءة الملف. الرجاء التحقق من صحة الملف وحاول مرة أخرى.');
resetFileUpload();
}
};
reader.onerror = function() {
showError('خطأ في قراءة الملف', 'تعذر قراءة الملف. الرجاء المحاولة مرة أخرى.');
resetFileUpload();
};
reader.readAsArrayBuffer(file);
}
function findColumnKey(row, possibleKeys) {
const existingKeys = Object.keys(row);
for (let key of possibleKeys) {
if (existingKeys.includes(key)) {
return key;
}
}
return null;
}
function sanitizePhoneNumber(phone) {
if (!phone) return null;
// Convert to string if it's a number
phone = phone.toString();
// Remove all non-digit characters
phone = phone.replace(/\D/g, '');
// Saudi number validation (966 + 9 digits)
if (phone.startsWith('966') && phone.length === 12) {
return phone;
}
// International format
if (phone.length >= 10 && phone.length <= 15) {
return phone;
}
return null;
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 بايت';
const k = 1024;
const sizes = ['بايت', 'كيلوبايت', 'ميجابايت', 'جيجابايت'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
function resetFileUpload() {
fileInput.value = '';
fileInfo.style.display = 'none';
studentsData = [];
uploadContainer.classList.remove('active', 'error');
selectFileBtn.innerHTML = '<i class="fas fa-folder-open"></i> اختر ملف';
selectFileBtn.disabled = false;
updatePreview();
updateSendButtonState();
updateSendInfo();
}
function updatePreview() {
if (studentsData.length === 0) {
studentList.style.display = 'none';
previewMessage.style.display = 'block';
previewMessage.textContent = 'سيتم عرض معاينة الرسائل هنا بعد تحميل الملف وإدخال نموذج الرسالة.';
previewCount.textContent = '';
return;
}
let message = messageTemplate.value;
if (!message) {
studentList.style.display = 'none';
previewMessage.style.display = 'block';
previewMessage.textContent = 'الرجاء إدخال نموذج الرسالة لمعاينة الرسائل.';
previewCount.textContent = '';
return;
}
studentList.innerHTML = '';
previewMessage.style.display = 'none';
studentList.style.display = 'block';
previewCount.textContent = `عرض ${Math.min(5, studentsData.length)} من ${studentsData.length}`;
// Show preview for first 5 students
const previewCountNum = Math.min(5, studentsData.length);
for (let i = 0; i < previewCountNum; i++) {
const student = studentsData[i];
const link = customLink.value || '{الرابط}';
const processedMessage = processMessage(message, student.name, link);
const li = document.createElement('li');
li.className = 'student-item';
li.innerHTML = `
<div style="flex: 1;">
<strong>${student.name}</strong>
<div style="font-size: 12px; color: #666; margin-top: 4px;">${formatPhoneNumber(student.phone)}</div>
</div>
<div style="max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
${processedMessage}
</div>
`;
studentList.appendChild(li);
}
if (studentsData.length > 5) {
const li = document.createElement('li');
li.className = 'student-item';
li.style.textAlign = 'center';
li.style.color = '#666';
li.textContent = ${studentsData.length - 5} طلاب آخرين...`;
studentList.appendChild(li);
}
}
function formatPhoneNumber(phone) {
// Format Saudi numbers
if (phone.startsWith('966')) {
return `+${phone.substring(0, 3)} ${phone.substring(3, 5)} ${phone.substring(5, 8)} ${phone.substring(8)}`;
}
return `+${phone}`;
}
function processMessage(template, name, link) {
const today = new Date();
const dateStr = `${today.getDate()}/${today.getMonth() + 1}/${today.getFullYear()}`;
return template
.replace(/{اسم الطالب}/g, name)
.replace(/{الرابط}/g, link)
.replace(/{الرقم}/g, '+966XXXXXXXXX')
.replace(/{التاريخ}/g, dateStr);
}
function updateSendButtonState() {
sendMessagesBtn.disabled = studentsData.length === 0 || !messageTemplate.value;
}
function updateSendInfo() {
if (studentsData.length > 0) {
sendInfo.textContent = `جاهز لإرسال ${studentsData.length} رسالة`;
} else {
sendInfo.textContent = '';
}
}
function insertAtCursor(textarea, text) {
const startPos = textarea.selectionStart;
const endPos = textarea.selectionEnd;
const beforeText = textarea.value.substring(0, startPos);
const afterText = textarea.value.substring(endPos, textarea.value.length);
textarea.value = beforeText + text + afterText;
textarea.selectionStart = startPos + text.length;
textarea.selectionEnd = startPos + text.length;
textarea.focus();
// Trigger input event to update preview
const event = new Event('input', { bubbles: true });
textarea.dispatchEvent(event);
}
function startSendingProcess() {
if (studentsData.length === 0 || !messageTemplate.value) return;
// Reset counters
successCounter = 0;
errorCounter = 0;
// Show progress modal
progressModal.style.display = 'flex';
progressBar.style.width = '0%';
successCount.textContent = '';
errorCount.textContent = '';
cancelSendingBtn.disabled = false;
const totalStudents = studentsData.length;
const link = customLink.value || '{الرابط}';
let currentIndex = 0;
sendingProcess = setInterval(() => {
if (currentIndex >= totalStudents) {
// Finished sending
clearInterval(sendingProcess);
sendingProcess = null;
// Show success message
progressModal.style.display = 'none';
if (errorCounter === 0) {
successMessage.textContent = `تم إرسال جميع الرسائل بنجاح إلى ${totalStudents} طالب!`;
} else {
successMessage.textContent = `تم إرسال ${successCounter} رسالة بنجاح من أصل ${totalStudents}.`;
}
showFinalStats();
successModal.style.display = 'flex';
return;
}
const student = studentsData[currentIndex];
const message = processMessage(messageTemplate.value, student.name, link);
// Update progress
const percent = Math.round(((currentIndex + 1) / totalStudents) * 100);
progressBar.style.width = `${percent}%`;
statusMessage.innerHTML = `جاري إرسال الرسالة إلى <strong>${student.name}</strong> (${currentIndex + 1}/${totalStudents})...`;
// Simulate sending (in a real app, you would call WhatsApp API)
setTimeout(() => {
// Randomly simulate failures (for demo purposes)
if (Math.random() < 0.1) {
errorCounter++;
errorCount.textContent = `رسائل غير مرسلة: ${errorCounter}`;
// Retry logic (for demo, just continue)
if (Math.random() < 0.5 && currentIndex < totalStudents) {
statusMessage.innerHTML = `<span class="error">فشل إرسال الرسالة إلى ${student.name} - جاري إعادة المحاولة...</span>`;
currentIndex--;
} else {
statusMessage.innerHTML = `<span class="error">فشل إرسال الرسالة إلى ${student.name} - سيتم تخطي هذا الطالب</span>`;
}
} else {
successCounter++;
successCount.textContent = `رسائل مرسلة: ${successCounter}`;
}
currentIndex++;
}, 1000);
}, 1500);
}
function showFinalStats() {
const total = successCounter + errorCounter;
finalStats.innerHTML = `
<div style="display: flex; justify-content: space-around; margin-top: 10px;">
<div>
<div style="font-size: 24px; color: var(--success-color);">${successCounter}</div>
<div style="font-size: 14px;">ناجحة</div>
</div>
<div>
<div style="font-size: 24px; color: var(--error-color);">${errorCounter}</div>
<div style="font-size: 14px;">فاشلة</div>
</div>
<div>
<div style="font-size: 24px; color: var(--secondary-color);">${total}</div>
<div style="font-size: 14px;">المجموع</div>
</div>
</div>
`;
}
function downloadReport() {
// Create a CSV report
let csvContent = "اسم الطالب,رقم الجوال,الحالة\n";
studentsData.forEach((student, index) => {
const status = index < successCounter ? "ناجح" : "فشل";
csvContent += `${student.name},${formatPhoneNumber(student.phone)},${status}\n`;
});
// Create download link
const blob = new Blob(["\uFEFF"+csvContent], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', `تقرير_إرسال_الرسائل_${new Date().toLocaleDateString('ar')}.csv`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
function downloadSampleFile() {
// Create sample Excel file data
const sampleData = [
['اسم الطالب', 'رقم الجوال', 'البريد الإلكتروني'],
['أحمد محمد', '966501234567', 'ahmed@example.com'],
['فاطمة علي', '966502345678', 'fatima@example.com'],
['محمد حسن', '966503456789', 'mohamed@example.com']
];
// Create workbook
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet(sampleData);
XLSX.utils.book_append_sheet(wb, ws, "الطلاب");
// Generate and download
XLSX.writeFile(wb, 'نموذج_قائمة_الطلاب.xlsx');
}
function showError(title, message) {
uploadContainer.classList.add('error');
errorModalTitle.textContent = title;
errorModalMessage.textContent = message;
errorModal.style.display = 'flex';
}
// Handle clicks outside modal to close it
window.addEventListener('click', function(event) {
if (event.target === progressModal) {
progressModal.style.display = 'none';
}
if (event.target === successModal) {
successModal.style.display = 'none';
}
if (event.target === errorModal) {
errorModal.style.display = 'none';
}
});
});
</script>
</body>
</html>