Spaces:
Running
Running
اريد لكل مستخدم ان يكون يكون له حساب خاص به و مكان يضع بيه رقم الواتساب الذي يريد عليه الاشعار بتاع التطبيق و ايضا مكان واتساب لارسال للشخص المتابع و مكان لمشاؤكة قائمة الادوية من خلال الواتساب - Initial Deployment
ad8da2e
verified
| <html lang="ar" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>منبه الدواء - تذكير بمواعيد الأدوية</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700;900&display=swap'); | |
| body { | |
| font-family: 'Tajawal', sans-serif; | |
| } | |
| .notification-badge { | |
| position: absolute; | |
| top: -5px; | |
| right: -5px; | |
| width: 20px; | |
| height: 20px; | |
| background-color: #EF4444; | |
| color: white; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 12px; | |
| } | |
| .medication-card { | |
| transition: all 0.3s ease; | |
| } | |
| .medication-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); | |
| } | |
| .notification { | |
| animation: slideIn 0.5s forwards; | |
| } | |
| @keyframes slideIn { | |
| from { | |
| transform: translateX(100%); | |
| opacity: 0; | |
| } | |
| to { | |
| transform: translateX(0); | |
| opacity: 1; | |
| } | |
| } | |
| .time-picker::-webkit-calendar-picker-indicator { | |
| filter: invert(1); | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 text-gray-800"> | |
| <!-- Login/Signup Modal --> | |
| <div id="authModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"> | |
| <div class="bg-white rounded-lg w-full max-w-md"> | |
| <div class="bg-indigo-600 text-white px-6 py-4 rounded-t-lg"> | |
| <h3 class="text-lg font-bold">تسجيل الدخول / إنشاء حساب</h3> | |
| </div> | |
| <div class="p-6"> | |
| <form id="authForm"> | |
| <div class="mb-4"> | |
| <label for="username" class="block text-gray-700 mb-2">اسم المستخدم</label> | |
| <input type="text" id="username" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="password" class="block text-gray-700 mb-2">كلمة المرور</label> | |
| <input type="password" id="password" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required> | |
| </div> | |
| <div class="mb-6"> | |
| <label for="whatsappNumber" class="block text-gray-700 mb-2">رقم واتساب</label> | |
| <input type="tel" id="whatsappNumber" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="مثال: 966501234567" required> | |
| </div> | |
| <div class="mb-6"> | |
| <label for="caretakerNumber" class="block text-gray-700 mb-2">رقم المتابع (اختياري)</label> | |
| <input type="tel" id="caretakerNumber" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="مثال: 966501234567"> | |
| </div> | |
| <div class="flex justify-between space-x-4 space-x-reverse"> | |
| <button type="button" id="loginBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">تسجيل الدخول</button> | |
| <button type="button" id="signupBtn" class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700">إنشاء حساب</button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="container mx-auto px-4 py-8 max-w-6xl"> | |
| <!-- Header --> | |
| <header class="flex justify-between items-center mb-8"> | |
| <div> | |
| <h1 class="text-3xl font-bold text-indigo-700">منبه الدواء</h1> | |
| <p class="text-gray-600">تذكير بمواعيد الأدوية</p> | |
| </div> | |
| <div class="flex items-center space-x-4 space-x-reverse"> | |
| <div class="relative"> | |
| <button id="profileBtn" class="p-2 rounded-full bg-indigo-100 text-indigo-700 hover:bg-indigo-200"> | |
| <i class="fas fa-user"></i> | |
| </button> | |
| </div> | |
| <div class="relative"> | |
| <button id="notificationBtn" class="p-2 rounded-full bg-indigo-100 text-indigo-700 hover:bg-indigo-200"> | |
| <i class="fas fa-bell"></i> | |
| </button> | |
| <span id="notificationCount" class="notification-badge hidden">0</span> | |
| </div> | |
| <button id="addMedBtn" class="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 flex items-center"> | |
| <i class="fas fa-plus ml-2"></i> | |
| <span>إضافة دواء</span> | |
| </button> | |
| </div> | |
| </header> | |
| <!-- Notification Panel (Hidden by default) --> | |
| <div id="notificationPanel" class="hidden fixed top-20 right-4 w-80 bg-white shadow-lg rounded-lg z-50 overflow-hidden"> | |
| <div class="bg-indigo-600 text-white px-4 py-3 flex justify-between items-center"> | |
| <h3 class="font-bold">الإشعارات</h3> | |
| <button id="closeNotificationBtn" class="text-white hover:text-indigo-200"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div id="notificationList" class="max-h-96 overflow-y-auto"> | |
| <!-- Notifications will be added here dynamically --> | |
| <div class="p-4 text-center text-gray-500">لا توجد إشعارات</div> | |
| </div> | |
| </div> | |
| <!-- Stats Cards --> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8"> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-green-100 text-green-600 mr-4"> | |
| <i class="fas fa-check-circle text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500">الجرعات المأخوذة</p> | |
| <h3 class="text-2xl font-bold" id="takenCount">0</h3> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-red-100 text-red-600 mr-4"> | |
| <i class="fas fa-times-circle text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500">الجرعات الفائتة</p> | |
| <h3 class="text-2xl font-bold" id="missedCount">0</h3> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-blue-100 text-blue-600 mr-4"> | |
| <i class="fas fa-pills text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500">إجمالي الأدوية</p> | |
| <h3 class="text-2xl font-bold" id="totalMedsCount">0</h3> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Upcoming Medications --> | |
| <div class="mb-8"> | |
| <h2 class="text-xl font-bold mb-4 flex items-center"> | |
| <i class="fas fa-clock text-indigo-600 ml-2"></i> | |
| <span>الجرعات القادمة</span> | |
| </h2> | |
| <div id="upcomingMeds" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> | |
| <!-- Upcoming meds will be added here dynamically --> | |
| <div class="bg-white p-4 rounded-lg shadow text-center text-gray-500"> | |
| لا توجد جرعات قادمة | |
| </div> | |
| </div> | |
| </div> | |
| <!-- All Medications --> | |
| <div> | |
| <h2 class="text-xl font-bold mb-4 flex items-center"> | |
| <i class="fas fa-list-ul text-indigo-600 ml-2"></i> | |
| <span>جميع الأدوية</span> | |
| </h2> | |
| <div id="allMedsList" class="space-y-4"> | |
| <!-- All meds will be added here dynamically --> | |
| <div class="bg-white p-4 rounded-lg shadow text-center text-gray-500"> | |
| لا توجد أدوية مسجلة | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Add Medication Modal --> | |
| <div id="addMedModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"> | |
| <div class="bg-white rounded-lg w-full max-w-md"> | |
| <div class="bg-indigo-600 text-white px-6 py-4 rounded-t-lg flex justify-between items-center"> | |
| <h3 class="text-lg font-bold">إضافة دواء جديد</h3> | |
| <button id="closeModalBtn" class="text-white hover:text-indigo-200"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="p-6"> | |
| <form id="medicationForm"> | |
| <div class="mb-4"> | |
| <label for="medName" class="block text-gray-700 mb-2">اسم الدواء</label> | |
| <input type="text" id="medName" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="medDosage" class="block text-gray-700 mb-2">الجرعة</label> | |
| <input type="text" id="medDosage" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="مثال: حبة واحدة، ملعقة صغيرة" required> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="medTime" class="block text-gray-700 mb-2">الوقت</label> | |
| <input type="time" id="medTime" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 time-picker" required> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="medFrequency" class="block text-gray-700 mb-2">التكرار</label> | |
| <select id="medFrequency" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required> | |
| <option value="daily">يومي</option> | |
| <option value="weekly">أسبوعي</option> | |
| <option value="monthly">شهري</option> | |
| <option value="custom">مخصص</option> | |
| </select> | |
| </div> | |
| <div class="mb-4 hidden" id="customDaysContainer"> | |
| <label class="block text-gray-700 mb-2">أيام الأسبوع</label> | |
| <div class="grid grid-cols-7 gap-2"> | |
| <label class="flex items-center justify-center p-2 border rounded-lg cursor-pointer"> | |
| <input type="checkbox" name="customDays" value="0" class="hidden"> | |
| <span>الأحد</span> | |
| </label> | |
| <label class="flex items-center justify-center p-2 border rounded-lg cursor-pointer"> | |
| <input type="checkbox" name="customDays" value="1" class="hidden"> | |
| <span>الاثنين</span> | |
| </label> | |
| <label class="flex items-center justify-center p-2 border rounded-lg cursor-pointer"> | |
| <input type="checkbox" name="customDays" value="2" class="hidden"> | |
| <span>الثلاثاء</span> | |
| </label> | |
| <label class="flex items-center justify-center p-2 border rounded-lg cursor-pointer"> | |
| <input type="checkbox" name="customDays" value="3" class="hidden"> | |
| <span>الأربعاء</span> | |
| </label> | |
| <label class="flex items-center justify-center p-2 border rounded-lg cursor-pointer"> | |
| <input type="checkbox" name="customDays" value="4" class="hidden"> | |
| <span>الخميس</span> | |
| </label> | |
| <label class="flex items-center justify-center p-2 border rounded-lg cursor-pointer"> | |
| <input type="checkbox" name="customDays" value="5" class="hidden"> | |
| <span>الجمعة</span> | |
| </label> | |
| <label class="flex items-center justify-center p-2 border rounded-lg cursor-pointer"> | |
| <input type="checkbox" name="customDays" value="6" class="hidden"> | |
| <span>السبت</span> | |
| </label> | |
| </div> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="medNotes" class="block text-gray-700 mb-2">ملاحظات (اختياري)</label> | |
| <textarea id="medNotes" rows="3" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"></textarea> | |
| </div> | |
| <div class="mb-6"> | |
| <label class="flex items-center"> | |
| <input type="checkbox" id="enableWhatsApp" class="form-checkbox h-5 w-5 text-indigo-600"> | |
| <span class="mr-2 text-gray-700">إرسال تذكير عبر واتساب</span> | |
| </label> | |
| </div> | |
| <div id="whatsappSection" class="hidden mb-6"> | |
| <div class="mb-4"> | |
| <label for="whatsappNumber" class="block text-gray-700 mb-2">رقم واتساب المريض</label> | |
| <input type="tel" id="whatsappNumber" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="مثال: 966501234567"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="secondaryContact" class="block text-gray-700 mb-2">رقم واتساب للشخص المساعد (اختياري)</label> | |
| <input type="tel" id="secondaryContact" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="مثال: 966501234567"> | |
| </div> | |
| </div> | |
| <div class="flex justify-end space-x-4 space-x-reverse"> | |
| <button type="button" id="cancelMedBtn" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-100">إلغاء</button> | |
| <button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">حفظ الدواء</button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Confirmation Modal --> | |
| <div id="confirmModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"> | |
| <div class="bg-white rounded-lg w-full max-w-md"> | |
| <div class="bg-indigo-600 text-white px-6 py-4 rounded-t-lg"> | |
| <h3 class="text-lg font-bold">تأكيد أخذ الدواء</h3> | |
| </div> | |
| <div class="p-6"> | |
| <p id="confirmMessage" class="mb-6">هل أخذت دواء <span class="font-bold">[اسم الدواء]</span> في الوقت المحدد؟</p> | |
| <div class="flex justify-end space-x-4 space-x-reverse"> | |
| <button id="missedBtn" class="px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600">فوتتني الجرعة</button> | |
| <button id="takenBtn" class="px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600">نعم، أخذتها</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Sample data for medications | |
| let medications = JSON.parse(localStorage.getItem('medications')) || []; | |
| let notifications = JSON.parse(localStorage.getItem('notifications')) || []; | |
| let stats = JSON.parse(localStorage.getItem('stats')) || { taken: 0, missed: 0 }; | |
| // DOM Elements | |
| const addMedBtn = document.getElementById('addMedBtn'); | |
| const addMedModal = document.getElementById('addMedModal'); | |
| const closeModalBtn = document.getElementById('closeModalBtn'); | |
| const cancelMedBtn = document.getElementById('cancelMedBtn'); | |
| const medicationForm = document.getElementById('medicationForm'); | |
| const medFrequency = document.getElementById('medFrequency'); | |
| const customDaysContainer = document.getElementById('customDaysContainer'); | |
| const enableWhatsApp = document.getElementById('enableWhatsApp'); | |
| const whatsappSection = document.getElementById('whatsappSection'); | |
| const notificationBtn = document.getElementById('notificationBtn'); | |
| const notificationPanel = document.getElementById('notificationPanel'); | |
| const closeNotificationBtn = document.getElementById('closeNotificationBtn'); | |
| const notificationList = document.getElementById('notificationList'); | |
| const notificationCount = document.getElementById('notificationCount'); | |
| const confirmModal = document.getElementById('confirmModal'); | |
| const confirmMessage = document.getElementById('confirmMessage'); | |
| const takenBtn = document.getElementById('takenBtn'); | |
| const missedBtn = document.getElementById('missedBtn'); | |
| const takenCount = document.getElementById('takenCount'); | |
| const missedCount = document.getElementById('missedCount'); | |
| const totalMedsCount = document.getElementById('totalMedsCount'); | |
| const upcomingMeds = document.getElementById('upcomingMeds'); | |
| const allMedsList = document.getElementById('allMedsList'); | |
| // Current medication being confirmed | |
| let currentMedication = null; | |
| // Event Listeners | |
| addMedBtn.addEventListener('click', () => addMedModal.classList.remove('hidden')); | |
| closeModalBtn.addEventListener('click', () => addMedModal.classList.add('hidden')); | |
| cancelMedBtn.addEventListener('click', () => addMedModal.classList.add('hidden')); | |
| medFrequency.addEventListener('change', function() { | |
| if (this.value === 'custom') { | |
| customDaysContainer.classList.remove('hidden'); | |
| } else { | |
| customDaysContainer.classList.add('hidden'); | |
| } | |
| }); | |
| enableWhatsApp.addEventListener('change', function() { | |
| if (this.checked) { | |
| whatsappSection.classList.remove('hidden'); | |
| } else { | |
| whatsappSection.classList.add('hidden'); | |
| } | |
| }); | |
| medicationForm.addEventListener('submit', addMedication); | |
| notificationBtn.addEventListener('click', toggleNotificationPanel); | |
| closeNotificationBtn.addEventListener('click', () => notificationPanel.classList.add('hidden')); | |
| takenBtn.addEventListener('click', confirmTaken); | |
| missedBtn.addEventListener('click', confirmMissed); | |
| // Custom day checkboxes styling | |
| document.querySelectorAll('[name="customDays"]').forEach(checkbox => { | |
| const label = checkbox.parentElement; | |
| checkbox.addEventListener('change', function() { | |
| if (this.checked) { | |
| label.classList.add('bg-indigo-100', 'border-indigo-500'); | |
| } else { | |
| label.classList.remove('bg-indigo-100', 'border-indigo-500'); | |
| } | |
| }); | |
| }); | |
| // Initialize the app | |
| function init() { | |
| updateStats(); | |
| renderMedications(); | |
| renderNotifications(); | |
| checkForDueMedications(); | |
| // Check for due medications every minute | |
| setInterval(checkForDueMedications, 60000); | |
| } | |
| // Add new medication | |
| function addMedication(e) { | |
| e.preventDefault(); | |
| const name = document.getElementById('medName').value; | |
| const dosage = document.getElementById('medDosage').value; | |
| const time = document.getElementById('medTime').value; | |
| const frequency = document.getElementById('medFrequency').value; | |
| const notes = document.getElementById('medNotes').value; | |
| const whatsappEnabled = document.getElementById('enableWhatsApp').checked; | |
| const whatsappNumber = document.getElementById('whatsappNumber').value; | |
| const secondaryContact = document.getElementById('secondaryContact').value; | |
| let days = []; | |
| if (frequency === 'custom') { | |
| document.querySelectorAll('[name="customDays"]:checked').forEach(checkbox => { | |
| days.push(parseInt(checkbox.value)); | |
| }); | |
| } else if (frequency === 'weekly') { | |
| days = [new Date().getDay()]; // Current day of week (0-6) | |
| } else if (frequency === 'monthly') { | |
| days = [new Date().getDate()]; // Current day of month (1-31) | |
| } | |
| const medication = { | |
| id: Date.now(), | |
| name, | |
| dosage, | |
| time, | |
| frequency, | |
| days, | |
| notes, | |
| whatsappEnabled, | |
| whatsappNumber, | |
| secondaryContact, | |
| createdAt: new Date().toISOString(), | |
| active: true | |
| }; | |
| medications.push(medication); | |
| saveMedications(); | |
| // Reset form | |
| medicationForm.reset(); | |
| addMedModal.classList.add('hidden'); | |
| // Update UI | |
| updateStats(); | |
| renderMedications(); | |
| // Schedule notifications for this medication | |
| scheduleMedicationNotifications(medication); | |
| } | |
| // Save medications to localStorage | |
| function saveMedications() { | |
| localStorage.setItem('medications', JSON.stringify(medications)); | |
| } | |
| // Save notifications to localStorage | |
| function saveNotifications() { | |
| localStorage.setItem('notifications', JSON.stringify(notifications)); | |
| } | |
| // Save stats to localStorage | |
| function saveStats() { | |
| localStorage.setItem('stats', JSON.stringify(stats)); | |
| } | |
| // Update statistics | |
| function updateStats() { | |
| takenCount.textContent = stats.taken; | |
| missedCount.textContent = stats.missed; | |
| totalMedsCount.textContent = medications.length; | |
| } | |
| // Render medications list | |
| function renderMedications() { | |
| // Clear existing | |
| allMedsList.innerHTML = ''; | |
| upcomingMeds.innerHTML = ''; | |
| if (medications.length === 0) { | |
| allMedsList.innerHTML = '<div class="bg-white p-4 rounded-lg shadow text-center text-gray-500">لا توجد أدوية مسجلة</div>'; | |
| upcomingMeds.innerHTML = '<div class="bg-white p-4 rounded-lg shadow text-center text-gray-500">لا توجد جرعات قادمة</div>'; | |
| return; | |
| } | |
| // Sort medications by time | |
| const sortedMeds = [...medications].sort((a, b) => { | |
| return a.time.localeCompare(b.time); | |
| }); | |
| // Filter active medications | |
| const activeMeds = sortedMeds.filter(med => med.active); | |
| // Render all medications | |
| activeMeds.forEach(med => { | |
| const medCard = createMedicationCard(med); | |
| allMedsList.appendChild(medCard); | |
| }); | |
| // Render upcoming medications (next 3) | |
| const now = new Date(); | |
| const currentTime = now.getHours() * 60 + now.getMinutes(); | |
| const upcoming = activeMeds | |
| .filter(med => { | |
| const [hours, minutes] = med.time.split(':').map(Number); | |
| const medTime = hours * 60 + minutes; | |
| return medTime >= currentTime; | |
| }) | |
| .slice(0, 3); | |
| if (upcoming.length === 0) { | |
| upcomingMeds.innerHTML = '<div class="bg-white p-4 rounded-lg shadow text-center text-gray-500">لا توجد جرعات قادمة</div>'; | |
| } else { | |
| upcoming.forEach(med => { | |
| const upcomingCard = createUpcomingCard(med); | |
| upcomingMeds.appendChild(upcomingCard); | |
| }); | |
| } | |
| } | |
| // Create medication card for all medications list | |
| function createMedicationCard(med) { | |
| const card = document.createElement('div'); | |
| card.className = 'bg-white p-4 rounded-lg shadow medication-card'; | |
| card.dataset.id = med.id; | |
| const frequencyText = { | |
| daily: 'يومي', | |
| weekly: 'أسبوعي', | |
| monthly: 'شهري', | |
| custom: 'مخصص' | |
| }[med.frequency]; | |
| let daysText = ''; | |
| if (med.frequency === 'custom' && med.days.length > 0) { | |
| const dayNames = ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت']; | |
| daysText = med.days.map(day => dayNames[day]).join('، '); | |
| } | |
| card.innerHTML = ` | |
| <div class="flex justify-between items-start mb-2"> | |
| <h3 class="font-bold text-lg">${med.name}</h3> | |
| <div class="flex space-x-2 space-x-reverse"> | |
| <button class="edit-btn p-1 text-indigo-600 hover:text-indigo-800" data-id="${med.id}"> | |
| <i class="fas fa-edit"></i> | |
| </button> | |
| <button class="delete-btn p-1 text-red-600 hover:text-red-800" data-id="${med.id}"> | |
| <i class="fas fa-trash-alt"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="flex items-center mb-2"> | |
| <i class="fas fa-bolt text-yellow-500 ml-2"></i> | |
| <span>${med.dosage}</span> | |
| </div> | |
| <div class="flex items-center mb-2"> | |
| <i class="fas fa-clock text-blue-500 ml-2"></i> | |
| <span>${med.time} - ${frequencyText}${daysText ? ' (' + daysText + ')' : ''}</span> | |
| </div> | |
| ${med.notes ? ` | |
| <div class="flex items-start mb-2"> | |
| <i class="fas fa-sticky-note text-green-500 ml-2 mt-1"></i> | |
| <span>${med.notes}</span> | |
| </div> | |
| ` : ''} | |
| ${med.whatsappEnabled ? ` | |
| <div class="flex items-center"> | |
| <i class="fab fa-whatsapp text-green-600 ml-2"></i> | |
| <span>يتم إرسال تذكير عبر واتساب</span> | |
| </div> | |
| ` : ''} | |
| `; | |
| // Add event listeners to buttons | |
| card.querySelector('.edit-btn').addEventListener('click', () => editMedication(med.id)); | |
| card.querySelector('.delete-btn').addEventListener('click', () => deleteMedication(med.id)); | |
| return card; | |
| } | |
| // Create upcoming medication card | |
| function createUpcomingCard(med) { | |
| const card = document.createElement('div'); | |
| card.className = 'bg-white p-4 rounded-lg shadow medication-card'; | |
| card.dataset.id = med.id; | |
| card.innerHTML = ` | |
| <div class="flex justify-between items-start mb-2"> | |
| <h3 class="font-bold text-lg">${med.name}</h3> | |
| <span class="bg-indigo-100 text-indigo-800 px-2 py-1 rounded text-sm">${med.time}</span> | |
| </div> | |
| <div class="flex items-center mb-2"> | |
| <i class="fas fa-bolt text-yellow-500 ml-2"></i> | |
| <span>${med.dosage}</span> | |
| </div> | |
| <div class="flex items-center"> | |
| <i class="fas fa-clock text-blue-500 ml-2"></i> | |
| <span>${med.frequency === 'daily' ? 'يومي' : med.frequency === 'weekly' ? 'أسبوعي' : 'شهري'}</span> | |
| </div> | |
| `; | |
| return card; | |
| } | |
| // Edit medication | |
| function editMedication(id) { | |
| const med = medications.find(m => m.id === id); | |
| if (!med) return; | |
| // Fill the form with medication data | |
| document.getElementById('medName').value = med.name; | |
| document.getElementById('medDosage').value = med.dosage; | |
| document.getElementById('medTime').value = med.time; | |
| document.getElementById('medFrequency').value = med.frequency; | |
| document.getElementById('medNotes').value = med.notes || ''; | |
| document.getElementById('enableWhatsApp').checked = med.whatsappEnabled; | |
| if (med.frequency === 'custom') { | |
| customDaysContainer.classList.remove('hidden'); | |
| // Check the appropriate day checkboxes | |
| med.days.forEach(day => { | |
| const checkbox = document.querySelector(`[name="customDays"][value="${day}"]`); | |
| if (checkbox) { | |
| checkbox.checked = true; | |
| checkbox.dispatchEvent(new Event('change')); | |
| } | |
| }); | |
| } | |
| if (med.whatsappEnabled) { | |
| whatsappSection.classList.remove('hidden'); | |
| document.getElementById('whatsappNumber').value = med.whatsappNumber || ''; | |
| document.getElementById('secondaryContact').value = med.secondaryContact || ''; | |
| } | |
| // Show the modal | |
| addMedModal.classList.remove('hidden'); | |
| // Remove the medication (will be re-added when form is submitted) | |
| medications = medications.filter(m => m.id !== id); | |
| } | |
| // Delete medication | |
| function deleteMedication(id) { | |
| if (confirm('هل أنت متأكد من حذف هذا الدواء؟')) { | |
| medications = medications.filter(m => m.id !== id); | |
| saveMedications(); | |
| renderMedications(); | |
| updateStats(); | |
| } | |
| } | |
| // Schedule notifications for a medication | |
| function scheduleMedicationNotifications(med) { | |
| // In a real app, we would use the browser's Notification API and set alarms | |
| // For this demo, we'll just simulate it | |
| } | |
| // Check for due medications | |
| function checkForDueMedications() { | |
| const now = new Date(); | |
| const currentTime = now.getHours() * 60 + now.getMinutes(); | |
| medications.forEach(med => { | |
| if (!med.active) return; | |
| const [hours, minutes] = med.time.split(':').map(Number); | |
| const medTime = hours * 60 + minutes; | |
| // Check if medication is due now (with 1 minute tolerance) | |
| if (Math.abs(currentTime - medTime) <= 1) { | |
| // Check if we already notified for this medication today | |
| const today = now.toDateString(); | |
| const alreadyNotified = notifications.some(n => | |
| n.medId === med.id && new Date(n.date).toDateString() === today | |
| ); | |
| if (!alreadyNotified) { | |
| // Create notification | |
| const notification = { | |
| id: Date.now(), | |
| medId: med.id, | |
| title: 'حان وقت الدواء', | |
| message: `حان وقت أخذ ${med.name} (${med.dosage})`, | |
| date: new Date().toISOString(), | |
| read: false | |
| }; | |
| notifications.push(notification); | |
| saveNotifications(); | |
| // Show notification | |
| showNotification(notification); | |
| // Update UI | |
| renderNotifications(); | |
| // If WhatsApp is enabled, send message (simulated) | |
| if (med.whatsappEnabled) { | |
| sendWhatsAppReminder(med); | |
| } | |
| // Show confirmation modal | |
| currentMedication = med; | |
| confirmMessage.innerHTML = `هل أخذت دواء <span class="font-bold">${med.name}</span> (${med.dosage}) في الوقت المحدد؟`; | |
| confirmModal.classList.remove('hidden'); | |
| } | |
| } | |
| }); | |
| } | |
| // Show notification | |
| function showNotification(notification) { | |
| // In a real app, we would use the browser's Notification API | |
| // For this demo, we'll just add it to our notification list | |
| // Play sound | |
| const audio = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-alarm-digital-clock-beep-989.mp3'); | |
| audio.play().catch(e => console.log('Audio play failed:', e)); | |
| } | |
| // Send WhatsApp reminder using API | |
| function sendWhatsAppReminder(med) { | |
| const message = `تذكير: حان وقت أخذ ${med.name} (${med.dosage})`; | |
| // Prepare API request data | |
| const requestData = { | |
| apiKey: 'EAAIoEPATD6QBPJc1eQOqVyrpmut0P2WUVUCfXNLlcSFl0KA5WuSeZCaV1SDaAuhZBGPZCz1B2Rc8szs3w0aqsVeMzZCrjBMHO67E2H2cPV6vxHlcI0gwdRuQOZCIKcGLYCWG9G0EAG8itMtpDzsDIiJFj6yHyZAtkKxL0KfJhyZBBDKNB1qhydFTZApZCchTAFHuovZAFCU0EQrBFKaLTib3GAZA9HzAEpz860PNsIYNjp7ZCUoX1u3S', | |
| message: message | |
| }; | |
| // Primary contact | |
| if (med.whatsappNumber) { | |
| requestData.phone = med.whatsappNumber; | |
| fetch('https://api.whatsapp.com/send', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(requestData) | |
| }) | |
| .catch(error => console.error('Error sending WhatsApp:', error)); | |
| } | |
| // Secondary contact | |
| if (med.secondaryContact) { | |
| requestData.phone = med.secondaryContact; | |
| fetch('https://api.whatsapp.com/send', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(requestData) | |
| }) | |
| .catch(error => console.error('Error sending WhatsApp to secondary contact:', error)); | |
| } | |
| } | |
| // Toggle notification panel | |
| function toggleNotificationPanel() { | |
| notificationPanel.classList.toggle('hidden'); | |
| // Mark all notifications as read when panel is opened | |
| if (!notificationPanel.classList.contains('hidden')) { | |
| notifications.forEach(n => n.read = true); | |
| saveNotifications(); | |
| renderNotifications(); | |
| } | |
| } | |
| // Render notifications | |
| function renderNotifications() { | |
| notificationList.innerHTML = ''; | |
| if (notifications.length === 0) { | |
| notificationList.innerHTML = '<div class="p-4 text-center text-gray-500">لا توجد إشعارات</div>'; | |
| notificationCount.classList.add('hidden'); | |
| return; | |
| } | |
| // Sort by date (newest first) | |
| const sortedNotifications = [...notifications].sort((a, b) => { | |
| return new Date(b.date) - new Date(a.date); | |
| }); | |
| // Show only the last 10 notifications | |
| const recentNotifications = sortedNotifications.slice(0, 10); | |
| recentNotifications.forEach(notif => { | |
| const med = medications.find(m => m.id === notif.medId); | |
| if (!med) return; | |
| const notifElement = document.createElement('div'); | |
| notifElement.className = `p-4 border-b ${notif.read ? 'bg-white' : 'bg-blue-50'}`; | |
| notifElement.innerHTML = ` | |
| <div class="flex justify-between items-start mb-1"> | |
| <h4 class="font-bold">${notif.title}</h4> | |
| <span class="text-xs text-gray-500">${formatDate(notif.date)}</span> | |
| </div> | |
| <p class="text-gray-700">${notif.message}</p> | |
| ${med.notes ? `<p class="text-sm text-gray-600 mt-1">ملاحظة: ${med.notes}</p>` : ''} | |
| `; | |
| notificationList.appendChild(notifElement); | |
| }); | |
| // Update notification badge | |
| const unreadCount = notifications.filter(n => !n.read).length; | |
| if (unreadCount > 0) { | |
| notificationCount.textContent = unreadCount; | |
| notificationCount.classList.remove('hidden'); | |
| } else { | |
| notificationCount.classList.add('hidden'); | |
| } | |
| } | |
| // Format date for display | |
| function formatDate(dateString) { | |
| const date = new Date(dateString); | |
| return date.toLocaleTimeString('ar-EG', { hour: '2-digit', minute: '2-digit' }); | |
| } | |
| // Confirm medication was taken | |
| function confirmTaken() { | |
| if (!currentMedication) return; | |
| stats.taken++; | |
| saveStats(); | |
| updateStats(); | |
| confirmModal.classList.add('hidden'); | |
| currentMedication = null; | |
| } | |
| // Confirm medication was missed | |
| function confirmMissed() { | |
| if (!currentMedication) return; | |
| stats.missed++; | |
| saveStats(); | |
| updateStats(); | |
| // Add missed notification | |
| const notification = { | |
| id: Date.now(), | |
| medId: currentMedication.id, | |
| title: 'جرعة فائتة', | |
| message: `فوتت جرعة ${currentMedication.name} (${currentMedication.dosage})`, | |
| date: new Date().toISOString(), | |
| read: false | |
| }; | |
| notifications.push(notification); | |
| saveNotifications(); | |
| renderNotifications(); | |
| confirmModal.classList.add('hidden'); | |
| currentMedication = null; | |
| } | |
| <!-- Profile Settings Modal --> | |
| <div id="profileModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"> | |
| <div class="bg-white rounded-lg w-full max-w-md"> | |
| <div class="bg-indigo-600 text-white px-6 py-4 rounded-t-lg flex justify-between items-center"> | |
| <h3 class="text-lg font-bold">إعدادات الحساب</h3> | |
| <button id="closeProfileBtn" class="text-white hover:text-indigo-200"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="p-6"> | |
| <div class="mb-4"> | |
| <label class="block text-gray-700 mb-2">اسم المستخدم</label> | |
| <p id="profileUsername" class="font-bold"></p> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="profileWhatsapp" class="block text-gray-700 mb-2">رقم واتساب</label> | |
| <input type="tel" id="profileWhatsapp" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="مثال: 966501234567"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="profileCaretaker" class="block text-gray-700 mb-2">رقم المتابع</label> | |
| <input type="tel" id="profileCaretaker" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="مثال: 966501234567"> | |
| </div> | |
| <div class="mb-4"> | |
| <label class="flex items-center"> | |
| <input type="checkbox" id="shareList" class="form-checkbox h-5 w-5 text-indigo-600"> | |
| <span class="mr-2 text-gray-700">مشاركة قائمة الأدوية مع المتابع</span> | |
| </label> | |
| </div> | |
| <div class="flex justify-end space-x-4 space-x-reverse"> | |
| <button id="logoutBtn" class="px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600">تسجيل الخروج</button> | |
| <button id="saveProfileBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">حفظ التغييرات</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| // Initialize the app | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Check if user is logged in | |
| const currentUser = JSON.parse(localStorage.getItem('currentUser')); | |
| if (!currentUser) { | |
| document.getElementById('authModal').classList.remove('hidden'); | |
| } else { | |
| init(); | |
| } | |
| }); | |
| // User authentication functions | |
| const users = JSON.parse(localStorage.getItem('users')) || []; | |
| document.getElementById('signupBtn').addEventListener('click', function() { | |
| const username = document.getElementById('username').value; | |
| const password = document.getElementById('password').value; | |
| const whatsapp = document.getElementById('whatsappNumber').value; | |
| const caretaker = document.getElementById('caretakerNumber').value; | |
| if (users.some(u => u.username === username)) { | |
| alert('اسم المستخدم موجود بالفعل'); | |
| return; | |
| } | |
| const newUser = { | |
| username, | |
| password, | |
| whatsapp, | |
| caretaker, | |
| shareList: false, | |
| medications: [] | |
| }; | |
| users.push(newUser); | |
| localStorage.setItem('users', JSON.stringify(users)); | |
| localStorage.setItem('currentUser', JSON.stringify(username)); | |
| document.getElementById('authModal').classList.add('hidden'); | |
| location.reload(); | |
| }); | |
| document.getElementById('loginBtn').addEventListener('click', function() { | |
| const username = document.getElementById('username').value; | |
| const password = document.getElementById('password').value; | |
| const user = users.find(u => u.username === username && u.password === password); | |
| if (!user) { | |
| alert('اسم المستخدم أو كلمة المرور غير صحيحة'); | |
| return; | |
| } | |
| localStorage.setItem('currentUser', JSON.stringify(username)); | |
| document.getElementById('authModal').classList.add('hidden'); | |
| location.reload(); | |
| }); | |
| // Profile functions | |
| document.getElementById('profileBtn').addEventListener('click', function() { | |
| const currentUser = JSON.parse(localStorage.getItem('currentUser')); | |
| const user = users.find(u => u.username === currentUser); | |
| document.getElementById('profileUsername').textContent = user.username; | |
| document.getElementById('profileWhatsapp').value = user.whatsapp; | |
| document.getElementById('profileCaretaker').value = user.caretaker || ''; | |
| document.getElementById('shareList').checked = user.shareList || false; | |
| document.getElementById('profileModal').classList.remove('hidden'); | |
| }); | |
| document.getElementById('closeProfileBtn').addEventListener('click', function() { | |
| document.getElementById('profileModal').classList.add('hidden'); | |
| }); | |
| document.getElementById('saveProfileBtn').addEventListener('click', function() { | |
| const currentUser = JSON.parse(localStorage.getItem('currentUser')); | |
| const userIndex = users.findIndex(u => u.username === currentUser); | |
| users[userIndex].whatsapp = document.getElementById('profileWhatsapp').value; | |
| users[userIndex].caretaker = document.getElementById('profileCaretaker').value; | |
| users[userIndex].shareList = document.getElementById('shareList').checked; | |
| localStorage.setItem('users', JSON.stringify(users)); | |
| document.getElementById('profileModal').classList.add('hidden'); | |
| }); | |
| document.getElementById('logoutBtn').addEventListener('click', function() { | |
| localStorage.removeItem('currentUser'); | |
| location.reload(); | |
| }); | |
| // Modify init function to load user-specific data | |
| function init() { | |
| const currentUser = JSON.parse(localStorage.getItem('currentUser')); | |
| const user = users.find(u => u.username === currentUser); | |
| // Load user's medications | |
| medications = user.medications || []; | |
| updateStats(); | |
| renderMedications(); | |
| renderNotifications(); | |
| checkForDueMedications(); | |
| setInterval(checkForDueMedications, 60000); | |
| } | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Youssef117/dwaa2a" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |