ruslan312 commited on
Commit
9ba306b
·
verified ·
1 Parent(s): 6ffe06c

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +946 -288
index.html CHANGED
@@ -3,400 +3,693 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>MedTrack - Medication Reminder</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: #4a89dc;
11
- --secondary: #3bafda;
12
- --success: #8cc152;
13
- --danger: #e9573f;
14
- --light: #f5f7fa;
15
- --dark: #434a54;
16
- --gray: #e6e9ed;
 
 
 
 
 
 
 
17
  }
18
 
19
  * {
20
  margin: 0;
21
  padding: 0;
22
  box-sizing: border-box;
23
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
24
  }
25
 
26
  body {
27
- background-color: #f9f9f9;
28
  color: var(--dark);
29
  line-height: 1.6;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  }
31
 
32
  .container {
33
- max-width: 800px;
34
  margin: 0 auto;
35
- padding: 20px;
 
 
 
 
 
 
36
  }
37
 
38
  header {
39
  display: flex;
40
  justify-content: space-between;
41
  align-items: center;
42
- margin-bottom: 30px;
43
- padding-bottom: 15px;
44
- border-bottom: 1px solid var(--gray);
45
  }
46
 
47
  .logo {
48
  display: flex;
49
  align-items: center;
50
- gap: 10px;
51
  }
52
 
53
- .logo i {
54
- color: var(--primary);
55
- font-size: 28px;
 
 
 
 
 
 
56
  }
57
 
58
- .logo h1 {
 
59
  font-size: 24px;
60
- font-weight: 600;
61
- color: var(--dark);
62
  }
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  .btn {
65
- padding: 10px 15px;
66
  border: none;
67
- border-radius: 5px;
68
  cursor: pointer;
69
- font-weight: 500;
70
- transition: all 0.3s ease;
71
  display: inline-flex;
72
  align-items: center;
73
- gap: 8px;
 
 
 
 
 
 
74
  }
75
 
76
  .btn-primary {
77
- background-color: var(--primary);
78
- color: white;
79
  }
80
 
81
  .btn-primary:hover {
82
- background-color: #3a70c2;
 
83
  }
84
 
85
  .btn-secondary {
86
- background-color: var(--secondary);
87
- color: white;
88
  }
89
 
90
  .btn-secondary:hover {
91
- background-color: #2a9ac7;
 
92
  }
93
 
94
  .btn-success {
95
- background-color: var(--success);
96
- color: white;
97
  }
98
 
99
  .btn-success:hover {
100
- background-color: #7aae4a;
 
101
  }
102
 
103
  .btn-danger {
104
- background-color: var(--danger);
105
- color: white;
106
  }
107
 
108
  .btn-danger:hover {
109
- background-color: #d8422d;
 
110
  }
111
 
112
  .btn-outline {
113
  background-color: transparent;
114
- border: 1px solid var(--gray);
115
  color: var(--dark);
 
116
  }
117
 
118
  .btn-outline:hover {
119
- background-color: var(--gray);
 
120
  }
121
 
122
  /* Dashboard Section */
123
  .dashboard {
124
- margin-bottom: 30px;
125
  }
126
 
127
  .stats {
128
  display: grid;
129
  grid-template-columns: repeat(3, 1fr);
130
- gap: 15px;
131
- margin-bottom: 20px;
132
  }
133
 
134
  .stat-card {
135
- background-color: white;
136
- padding: 20px;
137
- border-radius: 8px;
138
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
 
 
 
 
 
 
 
 
139
  }
140
 
141
  .stat-card h3 {
142
  font-size: 14px;
143
- color: #666;
144
- margin-bottom: 5px;
 
145
  }
146
 
147
  .stat-card p {
148
- font-size: 24px;
149
- font-weight: 600;
150
  }
151
 
152
  /* Upcoming Medications */
153
  .upcoming {
154
- background-color: white;
155
- border-radius: 8px;
156
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
157
- padding: 20px;
 
 
 
 
 
 
 
158
  }
159
 
160
  .section-title {
161
  display: flex;
162
  justify-content: space-between;
163
  align-items: center;
164
- margin-bottom: 20px;
165
  }
166
 
167
  .section-title h2 {
168
- font-size: 18px;
169
  font-weight: 600;
170
- }
171
-
172
- .medication-list {
173
- display: flex;
174
- flex-direction: column;
175
- gap: 15px;
176
- }
177
-
178
- .medication-item {
179
  display: flex;
180
  align-items: center;
181
- padding: 15px;
182
- border-radius: 8px;
183
- background-color: var(--light);
184
- transition: all 0.3s ease;
185
  }
186
 
187
- .medication-item:hover {
188
- transform: translateY(-2px);
189
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
190
  }
191
 
192
- .med-icon {
193
- width: 50px;
194
- height: 50px;
195
- background-color: var(--secondary);
196
- border-radius: 50%;
197
  display: flex;
198
- align-items: center;
199
- justify-content: center;
200
- margin-right: 15px;
201
- color: white;
202
- font-size: 20px;
203
- }
204
-
205
- .med-details {
206
- flex: 1;
207
- }
208
-
209
- .med-details h3 {
210
- font-size: 16px;
211
- margin-bottom: 5px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  }
213
 
214
- .med-details p {
215
- font-size: 14px;
216
- color: #666;
217
  }
218
 
219
- .med-time {
220
- display: flex;
221
  flex-direction: column;
222
- align-items: flex-end;
223
  }
224
 
225
- .med-time p {
226
- font-weight: 600;
227
- margin-bottom: 5px;
228
- }
229
-
230
- /* Modal */
231
- .modal {
232
- display: none;
233
- position: fixed;
234
- top: 0;
235
- left: 0;
236
- width: 100%;
237
- height: 100%;
238
- background-color: rgba(0, 0, 0, 0.5);
239
- z-index: 1000;
240
- justify-content: center;
241
- align-items: center;
242
- }
243
-
244
- .modal-content {
245
- background-color: white;
246
- padding: 25px;
247
- border-radius: 10px;
248
- width: 90%;
249
- max-width: 500px;
250
- max-height: 90vh;
251
- overflow-y: auto;
252
- }
253
-
254
- .modal-header {
255
- display: flex;
256
- justify-content: space-between;
257
- align-items: center;
258
- margin-bottom: 20px;
259
- }
260
-
261
- .modal-header h2 {
262
- font-size: 20px;
263
- }
264
-
265
- .close-btn {
266
- background: none;
267
- border: none;
268
- font-size: 24px;
269
- cursor: pointer;
270
- color: #666;
271
- }
272
-
273
- .form-group {
274
  margin-bottom: 20px;
275
  }
276
 
277
- .form-group label {
278
- display: block;
279
- margin-bottom: 8px;
280
- font-weight: 500;
281
- }
282
-
283
- .form-control {
284
- width: 100%;
285
- padding: 10px 15px;
286
- border: 1px solid var(--gray);
287
- border-radius: 5px;
288
- font-size: 16px;
289
- }
290
-
291
- .form-control:focus {
292
- outline: none;
293
- border-color: var(--primary);
294
- }
295
-
296
- .time-inputs {
297
- display: grid;
298
- grid-template-columns: 1fr 1fr;
299
- gap: 15px;
300
- }
301
-
302
- .modal-footer {
303
- display: flex;
304
- justify-content: flex-end;
305
- gap: 10px;
306
- margin-top: 20px;
307
- }
308
-
309
- /* Notification */
310
- .notification {
311
- position: fixed;
312
- bottom: 20px;
313
- right: 20px;
314
- background-color: var(--primary);
315
- color: white;
316
- padding: 15px 25px;
317
- border-radius: 8px;
318
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
319
- display: flex;
320
  align-items: center;
321
- gap: 10px;
322
- transform: translateY(100px);
323
- opacity: 0;
324
- transition: all 0.3s ease;
325
- z-index: 100;
326
- }
327
-
328
- .notification.show {
329
- transform: translateY(0);
330
- opacity: 1;
331
- }
332
-
333
- .notification i {
334
- font-size: 20px;
335
  }
336
 
337
- /* Responsive */
338
- @media (max-width: 768px) {
339
- .stats {
340
- grid-template-columns: 1fr;
341
- }
342
-
343
- .medication-item {
344
- flex-direction: column;
345
- text-align: center;
346
- }
347
-
348
- .med-icon {
349
- margin-right: 0;
350
- margin-bottom: 15px;
351
- }
352
-
353
- .med-time {
354
- align-items: center;
355
- margin-top: 10px;
356
- }
357
  }
358
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
  </head>
360
  <body>
 
 
 
 
 
361
  <div class="container">
362
  <header>
363
  <div class="logo">
364
- <i class="fas fa-pills"></i>
365
- <h1>MedTrack</h1>
 
 
 
 
 
366
  </div>
367
  <button class="btn btn-primary" id="addMedBtn">
368
  <i class="fas fa-plus"></i> Add Medication
369
  </button>
370
  </header>
371
 
 
 
 
 
 
 
 
 
 
372
  <section class="dashboard">
373
  <div class="stats">
374
- <div class="stat-card">
375
- <h3>Upcoming Today</h3>
376
  <p id="upcomingCount">3</p>
377
  </div>
378
- <div class="stat-card">
379
- <h3>Medications</h3>
380
  <p id="totalMeds">5</p>
381
  </div>
382
- <div class="stat-card">
383
- <h3>Adherence</h3>
384
  <p id="adherenceRate">92%</p>
385
  </div>
386
  </div>
387
  </section>
388
 
389
- <section class="upcoming">
390
  <div class="section-title">
391
  <h2><i class="far fa-clock"></i> Upcoming Medications</h2>
392
- <button class="btn btn-outline">
393
- <i class="fas fa-ellipsis-h"></i>
394
- </button>
 
 
395
  </div>
396
 
397
  <div class="medication-list" id="medicationList">
398
  <!-- Medication items will be added here dynamically -->
399
  </div>
 
 
 
 
 
 
 
 
 
400
  </section>
401
  </div>
402
 
@@ -404,20 +697,20 @@
404
  <div class="modal" id="addMedModal">
405
  <div class="modal-content">
406
  <div class="modal-header">
407
- <h2>Add New Medication</h2>
408
  <button class="close-btn" id="closeModal">&times;</button>
409
  </div>
410
  <form id="medicationForm">
411
  <div class="form-group">
412
- <label for="medName">Medication Name</label>
413
  <input type="text" id="medName" class="form-control" placeholder="e.g. Ibuprofen" required>
414
  </div>
415
  <div class="form-group">
416
- <label for="medDosage">Dosage</label>
417
  <input type="text" id="medDosage" class="form-control" placeholder="e.g. 200mg" required>
418
  </div>
419
  <div class="form-group">
420
- <label for="medFrequency">Frequency</label>
421
  <select id="medFrequency" class="form-control" required>
422
  <option value="">Select frequency</option>
423
  <option value="once">Once daily</option>
@@ -427,7 +720,7 @@
427
  </select>
428
  </div>
429
  <div class="form-group">
430
- <label>Times</label>
431
  <div class="time-inputs" id="timeInputs">
432
  <div>
433
  <input type="time" id="time1" class="form-control" required>
@@ -435,7 +728,7 @@
435
  </div>
436
  </div>
437
  <div class="form-group">
438
- <label for="medNotes">Notes (Optional)</label>
439
  <textarea id="medNotes" class="form-control" rows="3" placeholder="Special instructions..."></textarea>
440
  </div>
441
  <div class="modal-footer">
@@ -447,13 +740,13 @@
447
  </div>
448
 
449
  <!-- Notification -->
450
- <div class="notification" id="notification">
451
  <i class="fas fa-check-circle"></i>
452
  <span id="notificationText">Medication added successfully!</span>
453
  </div>
454
 
455
  <script>
456
- // Sample data for medications
457
  const sampleMedications = [
458
  {
459
  id: 1,
@@ -461,7 +754,9 @@
461
  dosage: "200mg",
462
  time: "08:00",
463
  isTaken: false,
464
- note: "Take with food"
 
 
465
  },
466
  {
467
  id: 2,
@@ -469,7 +764,9 @@
469
  dosage: "1000IU",
470
  time: "12:00",
471
  isTaken: false,
472
- note: "With lunch"
 
 
473
  },
474
  {
475
  id: 3,
@@ -477,13 +774,36 @@
477
  dosage: "1 tablet",
478
  time: "18:00",
479
  isTaken: false,
480
- note: ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
  }
482
  ];
483
 
484
  // DOM Elements
485
  const medicationList = document.getElementById('medicationList');
486
  const addMedBtn = document.getElementById('addMedBtn');
 
487
  const addMedModal = document.getElementById('addMedModal');
488
  const closeModal = document.getElementById('closeModal');
489
  const cancelBtn = document.getElementById('cancelBtn');
@@ -495,18 +815,197 @@
495
  const upcomingCount = document.getElementById('upcomingCount');
496
  const totalMeds = document.getElementById('totalMeds');
497
  const adherenceRate = document.getElementById('adherenceRate');
 
 
 
 
 
498
 
499
  // Current medications
500
  let medications = [...sampleMedications];
501
- let nextId = 4;
 
 
 
502
 
503
  // Initialize the app
504
  function init() {
505
  renderMedications();
506
  updateStats();
 
 
 
 
 
 
 
 
 
 
507
  checkNotifications();
508
  }
509
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
  // Render medications to the list
511
  function renderMedications() {
512
  medicationList.innerHTML = '';
@@ -516,18 +1015,43 @@
516
  return a.time.localeCompare(b.time);
517
  });
518
 
519
- sortedMeds.forEach(med => {
520
- if (!med.isTaken) {
 
 
 
 
 
 
 
 
521
  const medItem = document.createElement('div');
522
- medItem.className = 'medication-item';
523
  medItem.dataset.id = med.id;
 
524
 
525
  const [hours, minutes] = med.time.split(':');
526
- let timeDisplay = med.time;
527
  const hour = parseInt(hours);
528
  const amPm = hour >= 12 ? 'PM' : 'AM';
529
  const hour12 = hour % 12 || 12;
530
- timeDisplay = `${hour12}:${minutes} ${amPm}`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
531
 
532
  medItem.innerHTML = `
533
  <div class="med-icon">
@@ -535,22 +1059,42 @@
535
  </div>
536
  <div class="med-details">
537
  <h3>${med.name}</h3>
538
- <p>${med.dosage} ${med.note ? '· ' + med.note : ''}</p>
 
539
  </div>
540
- <div class="med-time">
541
- <p>${timeDisplay}</p>
542
- <button class="btn btn-success btn-sm take-btn">
543
- <i class="fas fa-check"></i> Taken
544
  </button>
545
  </div>
546
  `;
547
 
 
 
 
 
548
  medicationList.appendChild(medItem);
549
 
550
  // Add event listener to the take button
551
  medItem.querySelector('.take-btn').addEventListener('click', () => takeMedication(med.id));
552
- }
553
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
  }
555
 
556
  // Mark medication as taken
@@ -558,23 +1102,48 @@
558
  const index = medications.findIndex(med => med.id === id);
559
  if (index !== -1) {
560
  medications[index].isTaken = true;
 
561
  renderMedications();
562
  updateStats();
563
- showNotification(`Marked ${medications[index].name} as taken.`);
 
 
 
 
 
 
564
 
565
- // Schedule notification for next dose
566
- scheduleNextNotification(medications[index]);
 
 
567
  }
568
  }
569
 
570
- // Show notification to take medication
571
- function showNotification(message) {
 
 
572
  notificationText.textContent = message;
573
  notification.classList.add('show');
574
 
575
  setTimeout(() => {
576
  notification.classList.remove('show');
577
  }, 3000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
  }
579
 
580
  // Check if any medications are due
@@ -586,7 +1155,25 @@
586
 
587
  medications.forEach(med => {
588
  if (!med.isTaken && med.time === currentTime) {
589
- showNotification(`Time to take ${med.name} (${med.dosage})`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
590
  }
591
  });
592
  }
@@ -594,39 +1181,65 @@
594
  // Schedule next notification for recurring medications
595
  function scheduleNextNotification(medication) {
596
  // In a real app, this would schedule an actual notification
597
- console.log(`Setting reminder for next dose of ${medication.name} at ${medication.time}`);
 
 
598
  }
599
 
600
- // Update statistics
601
  function updateStats() {
602
  const total = medications.length;
603
  const upcoming = medications.filter(med => !med.isTaken).length;
604
  const taken = medications.filter(med => med.isTaken).length;
605
  const adherence = total > 0 ? Math.round((taken / total) * 100) : 0;
606
 
607
- upcomingCount.textContent = upcoming;
608
- totalMeds.textContent = total;
609
- adherenceRate.textContent = `${adherence}%`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
610
  }
611
 
612
- // Show modal
613
  function showModal() {
614
  addMedModal.style.display = 'flex';
615
  document.body.style.overflow = 'hidden';
 
616
  }
617
 
618
- // Hide modal
619
  function hideModal() {
620
- addMedModal.style.display = 'none';
621
- document.body.style.overflow = 'auto';
622
- medicationForm.reset();
623
- while (timeInputs.children.length > 1) {
624
- timeInputs.removeChild(timeInputs.lastChild);
625
- }
 
 
 
626
  }
627
 
628
- // Add new medication
629
  function addMedication(name, dosage, frequency, times, note) {
 
 
 
630
  times.forEach(time => {
631
  const newMed = {
632
  id: nextId++,
@@ -634,20 +1247,43 @@
634
  dosage,
635
  time,
636
  isTaken: false,
637
- note
 
 
638
  };
639
 
640
  medications.push(newMed);
 
 
 
 
 
641
  });
642
 
643
  renderMedications();
644
  updateStats();
645
- showNotification(`Added ${name} to your medications.`);
646
  hideModal();
647
  }
648
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
649
  // Event Listeners
650
  addMedBtn.addEventListener('click', showModal);
 
651
  closeModal.addEventListener('click', hideModal);
652
  cancelBtn.addEventListener('click', hideModal);
653
 
@@ -687,18 +1323,40 @@
687
  });
688
 
689
  if (times.length === 0) {
690
- alert('Please enter at least one time');
691
  return;
692
  }
693
 
694
  addMedication(name, dosage, frequency, times, note);
695
  });
696
 
 
 
 
 
 
 
 
 
 
 
697
  // Initialize the app
698
  init();
699
 
700
- // Check every minute for due medications
701
- setInterval(checkNotifications, 60000);
 
 
 
 
 
 
 
 
 
 
 
 
702
  </script>
703
- <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>
704
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>MedTrack - Premium Medication Reminder</title>
7
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
9
  <style>
10
  :root {
11
+ --primary: #6c5ce7;
12
+ --primary-light: #a29bfe;
13
+ --primary-dark: #5649c2;
14
+ --secondary: #00cec9;
15
+ --success: #00b894;
16
+ --danger: #d63031;
17
+ --warning: #fdcb6e;
18
+ --light: #f5f6fa;
19
+ --dark: #2d3436;
20
+ --gray: #636e72;
21
+ --gray-light: #dfe6e9;
22
+ --white: #ffffff;
23
+ --glass: rgba(255, 255, 255, 0.25);
24
+ --glass-border: rgba(255, 255, 255, 0.4);
25
  }
26
 
27
  * {
28
  margin: 0;
29
  padding: 0;
30
  box-sizing: border-box;
31
+ font-family: 'Poppins', sans-serif;
32
  }
33
 
34
  body {
35
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
36
  color: var(--dark);
37
  line-height: 1.6;
38
+ min-height: 100vh;
39
+ }
40
+
41
+ /* Floating background elements */
42
+ .bg-shapes {
43
+ position: fixed;
44
+ top: 0;
45
+ left: 0;
46
+ width: 100%;
47
+ height: 100%;
48
+ overflow: hidden;
49
+ z-index: -1;
50
+ }
51
+
52
+ .bg-shape {
53
+ position: absolute;
54
+ border-radius: 50%;
55
+ opacity: 0.1;
56
+ filter: blur(50px);
57
+ }
58
+
59
+ .shape-1 {
60
+ width: 400px;
61
+ height: 400px;
62
+ background: var(--primary);
63
+ top: -100px;
64
+ left: -100px;
65
+ }
66
+
67
+ .shape-2 {
68
+ width: 600px;
69
+ height: 600px;
70
+ background: var(--secondary);
71
+ bottom: -200px;
72
+ right: -200px;
73
  }
74
 
75
  .container {
76
+ max-width: 900px;
77
  margin: 0 auto;
78
+ padding: 30px;
79
+ animation: fadeIn 0.8s ease-out;
80
+ }
81
+
82
+ @keyframes fadeIn {
83
+ from { opacity: 0; transform: translateY(20px); }
84
+ to { opacity: 1; transform: translateY(0); }
85
  }
86
 
87
  header {
88
  display: flex;
89
  justify-content: space-between;
90
  align-items: center;
91
+ margin-bottom: 40px;
92
+ padding-bottom: 20px;
93
+ border-bottom: 1px solid rgba(255, 255, 255, 0.5);
94
  }
95
 
96
  .logo {
97
  display: flex;
98
  align-items: center;
99
+ gap: 15px;
100
  }
101
 
102
+ .logo-icon {
103
+ width: 50px;
104
+ height: 50px;
105
+ background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
106
+ border-radius: 12px;
107
+ display: flex;
108
+ align-items: center;
109
+ justify-content: center;
110
+ box-shadow: 0 8px 20px rgba(108, 92, 231, 0.3);
111
  }
112
 
113
+ .logo-icon i {
114
+ color: var(--white);
115
  font-size: 24px;
 
 
116
  }
117
 
118
+ .logo-text h1 {
119
+ font-size: 28px;
120
+ font-weight: 700;
121
+ background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
122
+ -webkit-background-clip: text;
123
+ -webkit-text-fill-color: transparent;
124
+ margin-bottom: 3px;
125
+ }
126
+
127
+ .logo-text p {
128
+ font-size: 12px;
129
+ color: var(--gray);
130
+ letter-spacing: 1px;
131
+ text-transform: uppercase;
132
+ }
133
+
134
+ /* Buttons */
135
  .btn {
136
+ padding: 12px 20px;
137
  border: none;
138
+ border-radius: 12px;
139
  cursor: pointer;
140
+ font-weight: 600;
141
+ transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
142
  display: inline-flex;
143
  align-items: center;
144
+ gap: 10px;
145
+ font-size: 14px;
146
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
147
+ }
148
+
149
+ .btn i {
150
+ font-size: 16px;
151
  }
152
 
153
  .btn-primary {
154
+ background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
155
+ color: var(--white);
156
  }
157
 
158
  .btn-primary:hover {
159
+ box-shadow: 0 8px 20px rgba(108, 92, 231, 0.4);
160
+ transform: translateY(-2px);
161
  }
162
 
163
  .btn-secondary {
164
+ background: linear-gradient(135deg, var(--secondary) 0%, #00a6b3 100%);
165
+ color: var(--white);
166
  }
167
 
168
  .btn-secondary:hover {
169
+ box-shadow: 0 8px 20px rgba(0, 206, 201, 0.4);
170
+ transform: translateY(-2px);
171
  }
172
 
173
  .btn-success {
174
+ background: linear-gradient(135deg, var(--success) 0%, #00967e 100%);
175
+ color: var(--white);
176
  }
177
 
178
  .btn-success:hover {
179
+ box-shadow: 0 8px 20px rgba(0, 184, 148, 0.4);
180
+ transform: translateY(-2px);
181
  }
182
 
183
  .btn-danger {
184
+ background: linear-gradient(135deg, var(--danger) 0%, #c02929 100%);
185
+ color: var(--white);
186
  }
187
 
188
  .btn-danger:hover {
189
+ box-shadow: 0 8px 20px rgba(214, 48, 49, 0.4);
190
+ transform: translateY(-2px);
191
  }
192
 
193
  .btn-outline {
194
  background-color: transparent;
195
+ border: 2px solid var(--glass-border);
196
  color: var(--dark);
197
+ backdrop-filter: blur(5px);
198
  }
199
 
200
  .btn-outline:hover {
201
+ background-color: var(--glass);
202
+ transform: translateY(-2px);
203
  }
204
 
205
  /* Dashboard Section */
206
  .dashboard {
207
+ margin-bottom: 40px;
208
  }
209
 
210
  .stats {
211
  display: grid;
212
  grid-template-columns: repeat(3, 1fr);
213
+ gap: 20px;
214
+ margin-bottom: 30px;
215
  }
216
 
217
  .stat-card {
218
+ background: var(--glass);
219
+ backdrop-filter: blur(10px);
220
+ border: 1px solid var(--glass-border);
221
+ padding: 25px;
222
+ border-radius: 16px;
223
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.1);
224
+ transition: all 0.3s ease;
225
+ }
226
+
227
+ .stat-card:hover {
228
+ transform: translateY(-5px);
229
+ box-shadow: 0 8px 20px rgba(108, 92, 231, 0.2);
230
  }
231
 
232
  .stat-card h3 {
233
  font-size: 14px;
234
+ font-weight: 500;
235
+ color: var(--gray);
236
+ margin-bottom: 10px;
237
  }
238
 
239
  .stat-card p {
240
+ font-size: 28px;
241
+ font-weight: 700;
242
  }
243
 
244
  /* Upcoming Medications */
245
  .upcoming {
246
+ background: var(--glass);
247
+ backdrop-filter: blur(10px);
248
+ border: 1px solid var(--glass-border);
249
+ border-radius: 16px;
250
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.1);
251
+ padding: 25px;
252
+ transition: all 0.3s ease;
253
+ }
254
+
255
+ .upcoming:hover {
256
+ box-shadow: 0 8px 20px rgba(108, 92, 231, 0.2);
257
  }
258
 
259
  .section-title {
260
  display: flex;
261
  justify-content: space-between;
262
  align-items: center;
263
+ margin-bottom: 25px;
264
  }
265
 
266
  .section-title h2 {
267
+ font-size: 20px;
268
  font-weight: 600;
 
 
 
 
 
 
 
 
 
269
  display: flex;
270
  align-items: center;
271
+ gap: 10px;
 
 
 
272
  }
273
 
274
+ .section-title i {
275
+ color: var(--primary);
 
276
  }
277
 
278
+ .medication-list {
 
 
 
 
279
  display: flex;
280
+ flex-direction: column;
281
+ gap: 15px;
282
+ }
283
+
284
+ .medication-item {
285
+ display: flex;
286
+ align-items: center;
287
+ padding: 20px;
288
+ border-radius: 12px;
289
+ background: var(--white);
290
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
291
+ transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
292
+ position: relative;
293
+ overflow: hidden;
294
+ }
295
+
296
+ .medication-item:hover {
297
+ transform: translateY(-3px);
298
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
299
+ }
300
+
301
+ .medication-item::before {
302
+ content: '';
303
+ position: absolute;
304
+ top: 0;
305
+ left: 0;
306
+ width: 5px;
307
+ height: 100%;
308
+ background: linear-gradient(to bottom, var(--primary), var(--secondary));
309
+ }
310
+
311
+ .med-icon {
312
+ width: 55px;
313
+ height: 55px;
314
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
315
+ border-radius: 12px;
316
+ display: flex;
317
+ align-items: center;
318
+ justify-content: center;
319
+ margin-right: 20px;
320
+ color: var(--white);
321
+ font-size: 22px;
322
+ box-shadow: 0 4px 15px rgba(108, 92, 231, 0.3);
323
+ }
324
+
325
+ .med-details {
326
+ flex: 1;
327
+ }
328
+
329
+ .med-details h3 {
330
+ font-size: 18px;
331
+ margin-bottom: 8px;
332
+ font-weight: 600;
333
+ }
334
+
335
+ .med-details p {
336
+ font-size: 14px;
337
+ color: var(--gray);
338
+ }
339
+
340
+ .med-note {
341
+ font-size: 13px;
342
+ color: var(--gray);
343
+ margin-top: 5px;
344
+ display: flex;
345
+ align-items: center;
346
+ gap: 5px;
347
+ }
348
+
349
+ .med-time {
350
+ display: flex;
351
+ flex-direction: column;
352
+ align-items: flex-end;
353
+ }
354
+
355
+ .med-time p {
356
+ font-weight: 600;
357
+ margin-bottom: 10px;
358
+ font-size: 15px;
359
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
360
+ -webkit-background-clip: text;
361
+ -webkit-text-fill-color: transparent;
362
+ }
363
+
364
+ /* Modal */
365
+ .modal {
366
+ display: none;
367
+ position: fixed;
368
+ top: 0;
369
+ left: 0;
370
+ width: 100%;
371
+ height: 100%;
372
+ background-color: rgba(45, 52, 54, 0.8);
373
+ z-index: 1000;
374
+ justify-content: center;
375
+ align-items: center;
376
+ backdrop-filter: blur(5px);
377
+ animation: fadeIn 0.3s ease-out;
378
+ }
379
+
380
+ .modal-content {
381
+ background: var(--white);
382
+ padding: 30px;
383
+ border-radius: 20px;
384
+ width: 90%;
385
+ max-width: 500px;
386
+ max-height: 90vh;
387
+ overflow-y: auto;
388
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
389
+ transform: translateY(0);
390
+ transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
391
+ }
392
+
393
+ .modal.show .modal-content {
394
+ animation: modalSlideIn 0.4s ease-out;
395
+ }
396
+
397
+ @keyframes modalSlideIn {
398
+ from { transform: translateY(50px); opacity: 0; }
399
+ to { transform: translateY(0); opacity: 1; }
400
+ }
401
+
402
+ .modal-header {
403
+ display: flex;
404
+ justify-content: space-between;
405
+ align-items: center;
406
+ margin-bottom: 25px;
407
+ }
408
+
409
+ .modal-header h2 {
410
+ font-size: 24px;
411
+ font-weight: 600;
412
+ color: var(--primary);
413
+ }
414
+
415
+ .close-btn {
416
+ background: none;
417
+ border: none;
418
+ font-size: 28px;
419
+ cursor: pointer;
420
+ color: var(--gray);
421
+ transition: all 0.3s ease;
422
+ }
423
+
424
+ .close-btn:hover {
425
+ color: var(--danger);
426
+ transform: rotate(90deg);
427
+ }
428
+
429
+ .form-group {
430
+ margin-bottom: 25px;
431
+ }
432
+
433
+ .form-group label {
434
+ display: block;
435
+ margin-bottom: 10px;
436
+ font-weight: 500;
437
+ color: var(--dark);
438
+ }
439
+
440
+ .form-control {
441
+ width: 100%;
442
+ padding: 14px 20px;
443
+ border: 2px solid var(--gray-light);
444
+ border-radius: 12px;
445
+ font-size: 16px;
446
+ transition: all 0.3s ease;
447
+ background-color: var(--light);
448
+ }
449
+
450
+ .form-control:focus {
451
+ outline: none;
452
+ border-color: var(--primary);
453
+ box-shadow: 0 0 0 3px rgba(108, 92, 231, 0.2);
454
+ }
455
+
456
+ .time-inputs {
457
+ display: grid;
458
+ grid-template-columns: 1fr 1fr;
459
+ gap: 15px;
460
+ }
461
+
462
+ textarea.form-control {
463
+ min-height: 100px;
464
+ resize: vertical;
465
+ }
466
+
467
+ .modal-footer {
468
+ display: flex;
469
+ justify-content: flex-end;
470
+ gap: 15px;
471
+ margin-top: 30px;
472
+ }
473
+
474
+ /* Notification */
475
+ .notification {
476
+ position: fixed;
477
+ bottom: 30px;
478
+ right: 30px;
479
+ background: linear-gradient(135deg, var(--success) 0%, #00967e 100%);
480
+ color: var(--white);
481
+ padding: 18px 30px;
482
+ border-radius: 12px;
483
+ box-shadow: 0 10px 30px rgba(0, 184, 148, 0.3);
484
+ display: flex;
485
+ align-items: center;
486
+ gap: 15px;
487
+ transform: translateX(150%);
488
+ opacity: 0;
489
+ transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
490
+ z-index: 100;
491
+ }
492
+
493
+ .notification.show {
494
+ transform: translateX(0);
495
+ opacity: 1;
496
+ }
497
+
498
+ .notification i {
499
+ font-size: 24px;
500
+ }
501
+
502
+ .notification.success {
503
+ background: linear-gradient(135deg, var(--success) 0%, #00967e 100%);
504
+ }
505
+
506
+ .notification.warning {
507
+ background: linear-gradient(135deg, var(--warning) 0%, #f8a84a 100%);
508
+ }
509
+
510
+ .notification.error {
511
+ background: linear-gradient(135deg, var(--danger) 0%, #c02929 100%);
512
+ }
513
+
514
+ /* Empty state */
515
+ .empty-state {
516
+ text-align: center;
517
+ padding: 40px 0;
518
+ }
519
+
520
+ .empty-state i {
521
+ font-size: 60px;
522
+ color: var(--gray-light);
523
+ margin-bottom: 20px;
524
+ }
525
+
526
+ .empty-state h3 {
527
+ font-size: 18px;
528
+ color: var(--gray);
529
+ margin-bottom: 10px;
530
+ }
531
+
532
+ .empty-state p {
533
+ font-size: 14px;
534
+ color: var(--gray-light);
535
+ margin-bottom: 20px;
536
+ }
537
+
538
+ /* Notification permissions section */
539
+ .notification-permission {
540
+ background: var(--glass);
541
+ backdrop-filter: blur(10px);
542
+ border: 1px solid var(--glass-border);
543
+ border-radius: 16px;
544
+ padding: 20px;
545
+ margin-bottom: 30px;
546
+ display: flex;
547
+ justify-content: space-between;
548
+ align-items: center;
549
+ animation: fadeIn 0.6s ease-out;
550
+ }
551
+
552
+ .notification-permission p {
553
+ font-size: 14px;
554
+ color: var(--gray);
555
+ display: flex;
556
+ align-items: center;
557
+ gap: 10px;
558
+ }
559
+
560
+ .notification-permission i {
561
+ color: var(--warning);
562
+ font-size: 18px;
563
+ }
564
+
565
+ /* Responsive */
566
+ @media (max-width: 768px) {
567
+ .container {
568
+ padding: 20px;
569
  }
570
 
571
+ .stats {
572
+ grid-template-columns: 1fr;
 
573
  }
574
 
575
+ .medication-item {
 
576
  flex-direction: column;
577
+ text-align: center;
578
  }
579
 
580
+ .med-icon {
581
+ margin-right: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
582
  margin-bottom: 20px;
583
  }
584
 
585
+ .med-time {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
586
  align-items: center;
587
+ margin-top: 15px;
 
 
 
 
 
 
 
 
 
 
 
 
 
588
  }
589
 
590
+ .time-inputs {
591
+ grid-template-columns: 1fr;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
  }
593
+ }
594
+
595
+ /* Animation on scroll */
596
+ .animate-on-scroll {
597
+ opacity: 0;
598
+ transform: translateY(30px);
599
+ transition: all 0.6s ease-out;
600
+ }
601
+
602
+ .animate-on-scroll.show {
603
+ opacity: 1;
604
+ transform: translateY(0);
605
+ }
606
+
607
+ /* Loading spinner */
608
+ .spinner {
609
+ display: inline-block;
610
+ width: 20px;
611
+ height: 20px;
612
+ border: 3px solid rgba(255,255,255,.3);
613
+ border-radius: 50%;
614
+ border-top-color: var(--white);
615
+ animation: spin 1s ease-in-out infinite;
616
+ }
617
+
618
+ @keyframes spin {
619
+ to { transform: rotate(360deg); }
620
+ }
621
+ </style>
622
  </head>
623
  <body>
624
+ <div class="bg-shapes">
625
+ <div class="bg-shape shape-1"></div>
626
+ <div class="bg-shape shape-2"></div>
627
+ </div>
628
+
629
  <div class="container">
630
  <header>
631
  <div class="logo">
632
+ <div class="logo-icon">
633
+ <i class="fas fa-pills"></i>
634
+ </div>
635
+ <div class="logo-text">
636
+ <h1>MedTrack</h1>
637
+ <p>Premium Medication Manager</p>
638
+ </div>
639
  </div>
640
  <button class="btn btn-primary" id="addMedBtn">
641
  <i class="fas fa-plus"></i> Add Medication
642
  </button>
643
  </header>
644
 
645
+ <!-- Notification Permission Banner -->
646
+ <div class="notification-permission animate-on-scroll" id="permissionBanner" style="display: none;">
647
+ <p><i class="fas fa-bell"></i> Enable notifications to get reminders for your medications</p>
648
+ <button class="btn btn-warning" id="enableNotifications">
649
+ <span id="enableNotificationsText">Enable Notifications</span>
650
+ <span class="spinner" id="notificationSpinner" style="display: none;"></span>
651
+ </button>
652
+ </div>
653
+
654
  <section class="dashboard">
655
  <div class="stats">
656
+ <div class="stat-card animate-on-scroll">
657
+ <h3><i class="fas fa-clock"></i> Upcoming Today</h3>
658
  <p id="upcomingCount">3</p>
659
  </div>
660
+ <div class="stat-card animate-on-scroll" style="transition-delay: 0.1s;">
661
+ <h3><i class="fas fa-prescription-bottle-alt"></i> Medications</h3>
662
  <p id="totalMeds">5</p>
663
  </div>
664
+ <div class="stat-card animate-on-scroll" style="transition-delay: 0.2s;">
665
+ <h3><i class="fas fa-check-circle"></i> Adherence</h3>
666
  <p id="adherenceRate">92%</p>
667
  </div>
668
  </div>
669
  </section>
670
 
671
+ <section class="upcoming animate-on-scroll">
672
  <div class="section-title">
673
  <h2><i class="far fa-clock"></i> Upcoming Medications</h2>
674
+ <div class="dropdown">
675
+ <button class="btn btn-outline">
676
+ <i class="fas fa-ellipsis-v"></i>
677
+ </button>
678
+ </div>
679
  </div>
680
 
681
  <div class="medication-list" id="medicationList">
682
  <!-- Medication items will be added here dynamically -->
683
  </div>
684
+
685
+ <div class="empty-state" id="emptyState" style="display: none;">
686
+ <i class="fas fa-cloud"></i>
687
+ <h3>No medications scheduled</h3>
688
+ <p>Add your first medication to get started</p>
689
+ <button class="btn btn-primary" id="addFirstMed">
690
+ <i class="fas fa-plus"></i> Add Medication
691
+ </button>
692
+ </div>
693
  </section>
694
  </div>
695
 
 
697
  <div class="modal" id="addMedModal">
698
  <div class="modal-content">
699
  <div class="modal-header">
700
+ <h2><i class="fas fa-plus-circle"></i> Add New Medication</h2>
701
  <button class="close-btn" id="closeModal">&times;</button>
702
  </div>
703
  <form id="medicationForm">
704
  <div class="form-group">
705
+ <label for="medName"><i class="fas fa-capsules"></i> Medication Name</label>
706
  <input type="text" id="medName" class="form-control" placeholder="e.g. Ibuprofen" required>
707
  </div>
708
  <div class="form-group">
709
+ <label for="medDosage"><i class="fas fa-prescription-bottle-alt"></i> Dosage</label>
710
  <input type="text" id="medDosage" class="form-control" placeholder="e.g. 200mg" required>
711
  </div>
712
  <div class="form-group">
713
+ <label for="medFrequency"><i class="fas fa-history"></i> Frequency</label>
714
  <select id="medFrequency" class="form-control" required>
715
  <option value="">Select frequency</option>
716
  <option value="once">Once daily</option>
 
720
  </select>
721
  </div>
722
  <div class="form-group">
723
+ <label><i class="far fa-clock"></i> Times</label>
724
  <div class="time-inputs" id="timeInputs">
725
  <div>
726
  <input type="time" id="time1" class="form-control" required>
 
728
  </div>
729
  </div>
730
  <div class="form-group">
731
+ <label for="medNotes"><i class="far fa-sticky-note"></i> Notes (Optional)</label>
732
  <textarea id="medNotes" class="form-control" rows="3" placeholder="Special instructions..."></textarea>
733
  </div>
734
  <div class="modal-footer">
 
740
  </div>
741
 
742
  <!-- Notification -->
743
+ <div class="notification success" id="notification">
744
  <i class="fas fa-check-circle"></i>
745
  <span id="notificationText">Medication added successfully!</span>
746
  </div>
747
 
748
  <script>
749
+ // Enhanced sample data for medications with more details
750
  const sampleMedications = [
751
  {
752
  id: 1,
 
754
  dosage: "200mg",
755
  time: "08:00",
756
  isTaken: false,
757
+ note: "Take with breakfast",
758
+ category: "Pain Relief",
759
+ lastTaken: null
760
  },
761
  {
762
  id: 2,
 
764
  dosage: "1000IU",
765
  time: "12:00",
766
  isTaken: false,
767
+ note: "With lunch for better absorption",
768
+ category: "Supplement",
769
+ lastTaken: null
770
  },
771
  {
772
  id: 3,
 
774
  dosage: "1 tablet",
775
  time: "18:00",
776
  isTaken: false,
777
+ note: "",
778
+ category: "Supplement",
779
+ lastTaken: null
780
+ },
781
+ {
782
+ id: 4,
783
+ name: "Propranolol",
784
+ dosage: "40mg",
785
+ time: "10:00",
786
+ isTaken: true,
787
+ note: "For blood pressure",
788
+ category: "Cardiac",
789
+ lastTaken: "2023-07-20T08:00:00"
790
+ },
791
+ {
792
+ id: 5,
793
+ name: "Omeprazole",
794
+ dosage: "20mg",
795
+ time: "07:30",
796
+ isTaken: true,
797
+ note: "Before breakfast",
798
+ category: "Gastrointestinal",
799
+ lastTaken: "2023-07-20T07:30:00"
800
  }
801
  ];
802
 
803
  // DOM Elements
804
  const medicationList = document.getElementById('medicationList');
805
  const addMedBtn = document.getElementById('addMedBtn');
806
+ const addFirstMed = document.getElementById('addFirstMed');
807
  const addMedModal = document.getElementById('addMedModal');
808
  const closeModal = document.getElementById('closeModal');
809
  const cancelBtn = document.getElementById('cancelBtn');
 
815
  const upcomingCount = document.getElementById('upcomingCount');
816
  const totalMeds = document.getElementById('totalMeds');
817
  const adherenceRate = document.getElementById('adherenceRate');
818
+ const emptyState = document.getElementById('emptyState');
819
+ const permissionBanner = document.getElementById('permissionBanner');
820
+ const enableNotificationsBtn = document.getElementById('enableNotifications');
821
+ const enableNotificationsText = document.getElementById('enableNotificationsText');
822
+ const notificationSpinner = document.getElementById('notificationSpinner');
823
 
824
  // Current medications
825
  let medications = [...sampleMedications];
826
+ let nextId = 6;
827
+ let notificationPermissionGranted = false;
828
+ let notificationCheckInterval;
829
+ let scheduledNotifications = {};
830
 
831
  // Initialize the app
832
  function init() {
833
  renderMedications();
834
  updateStats();
835
+ checkNotificationPermission();
836
+ setupIntersectionObserver();
837
+
838
+ // Request permission when clicking the notification button
839
+ enableNotificationsBtn.addEventListener('click', requestNotificationPermission);
840
+
841
+ // Check every minute for due medications
842
+ notificationCheckInterval = setInterval(checkNotifications, 60000);
843
+
844
+ // Initial check
845
  checkNotifications();
846
  }
847
 
848
+ // Check and request notification permission
849
+ function checkNotificationPermission() {
850
+ if (!('Notification' in window)) {
851
+ console.log('This browser does not support desktop notification');
852
+ return;
853
+ }
854
+
855
+ if (Notification.permission === 'granted') {
856
+ notificationPermissionGranted = true;
857
+ permissionBanner.style.display = 'none';
858
+ } else if (Notification.permission !== 'denied') {
859
+ // Show the permission banner
860
+ permissionBanner.style.display = 'flex';
861
+ setTimeout(() => permissionBanner.classList.add('show'), 100);
862
+ }
863
+ }
864
+
865
+ // Request notification permission
866
+ function requestNotificationPermission() {
867
+ enableNotificationsText.textContent = 'Loading...';
868
+ notificationSpinner.style.display = 'inline-block';
869
+
870
+ Notification.requestPermission().then(permission => {
871
+ enableNotificationsText.textContent = 'Enable Notifications';
872
+ notificationSpinner.style.display = 'none';
873
+
874
+ if (permission === 'granted') {
875
+ notificationPermissionGranted = true;
876
+ showNotification('Notifications enabled! You will now receive reminders for your medications.', 'success');
877
+ permissionBanner.style.display = 'none';
878
+
879
+ // Schedule all existing medication notifications
880
+ medications.forEach(med => {
881
+ if (!med.isTaken) {
882
+ scheduleSystemNotification(med);
883
+ }
884
+ });
885
+ } else {
886
+ showNotification('Notifications are disabled. You can enable them later in your browser settings.', 'warning');
887
+ }
888
+ }).catch(err => {
889
+ enableNotificationsText.textContent = 'Enable Notifications';
890
+ notificationSpinner.style.display = 'none';
891
+ console.error('Error requesting notification permission:', err);
892
+ showNotification('Failed to enable notifications. Please try again later.', 'error');
893
+ });
894
+ }
895
+
896
+ // Show system notification
897
+ function showSystemNotification(title, options) {
898
+ if (!notificationPermissionGranted) return;
899
+
900
+ try {
901
+ // Close any existing notification with the same tag
902
+ if (options.tag) {
903
+ const existingNotifications = Notification.notifications || [];
904
+ existingNotifications.forEach(notification => {
905
+ if (notification.tag === options.tag) {
906
+ notification.close();
907
+ }
908
+ });
909
+ }
910
+
911
+ // Show new notification
912
+ const notification = new Notification(title, options);
913
+
914
+ // Add click handler if supported
915
+ if ('onshow' in notification) {
916
+ notification.onshow = function() {
917
+ console.log('Notification shown:', title);
918
+ };
919
+ }
920
+
921
+ if ('onclick' in notification) {
922
+ notification.onclick = function() {
923
+ console.log('Notification clicked:', title);
924
+ window.focus();
925
+ // You could focus on the specific medication item
926
+ };
927
+ }
928
+
929
+ if ('onclose' in notification) {
930
+ notification.onclose = function() {
931
+ console.log('Notification closed:', title);
932
+ };
933
+ }
934
+
935
+ return notification;
936
+ } catch (error) {
937
+ console.error('Error showing notification:', error);
938
+ return null;
939
+ }
940
+ }
941
+
942
+ // Schedule system notification for medication
943
+ function scheduleSystemNotification(medication) {
944
+ if (!notificationPermissionGranted) return;
945
+
946
+ // Clear any existing notification for this medication
947
+ if (scheduledNotifications[medication.id]) {
948
+ clearTimeout(scheduledNotifications[medication.id]);
949
+ delete scheduledNotifications[medication.id];
950
+ }
951
+
952
+ // Parse the medication time
953
+ const [hours, minutes] = medication.time.split(':').map(Number);
954
+ const now = new Date();
955
+ const notificationTime = new Date();
956
+ notificationTime.setHours(hours);
957
+ notificationTime.setMinutes(minutes);
958
+ notificationTime.setSeconds(0);
959
+
960
+ // If the time is in the past, schedule for tomorrow
961
+ if (notificationTime < now) {
962
+ notificationTime.setDate(notificationTime.getDate() + 1);
963
+ }
964
+
965
+ const timeUntilNotification = notificationTime.getTime() - now.getTime();
966
+
967
+ if (timeUntilNotification > 0 && timeUntilNotification < 24 * 60 * 60 * 1000) {
968
+ scheduledNotifications[medication.id] = setTimeout(() => {
969
+ const title = `Time to take ${medication.name}`;
970
+ const options = {
971
+ body: `Dosage: ${medication.dosage}\n${medication.note || ''}`,
972
+ icon: 'https://cdn-icons-png.flaticon.com/512/3161/3161837.png',
973
+ tag: `medication-${medication.id}`,
974
+ requireInteraction: true,
975
+ vibrate: [200, 100, 200],
976
+ actions: [
977
+ {
978
+ action: 'mark-taken',
979
+ title: 'Mark as Taken',
980
+ icon: 'https://cdn-icons-png.flaticon.com/512/1828/1828640.png'
981
+ }
982
+ ]
983
+ };
984
+
985
+ const notif = showSystemNotification(title, options);
986
+
987
+ if (notif) {
988
+ notif.onclick = (event) => {
989
+ // If a specific action was clicked
990
+ if (event.action === 'mark-taken') {
991
+ takeMedication(medication.id);
992
+ } else {
993
+ // Otherwise, focus the window
994
+ window.focus();
995
+ }
996
+ notif.close();
997
+ };
998
+ }
999
+
1000
+ // Auto-fade notification after 5 minutes
1001
+ setTimeout(() => {
1002
+ if (notif) notif.close();
1003
+ }, 5 * 60 * 1000);
1004
+
1005
+ }, timeUntilNotification);
1006
+ }
1007
+ }
1008
+
1009
  // Render medications to the list
1010
  function renderMedications() {
1011
  medicationList.innerHTML = '';
 
1015
  return a.time.localeCompare(b.time);
1016
  });
1017
 
1018
+ const upcomingMeds = sortedMeds.filter(med => !med.isTaken);
1019
+
1020
+ if (upcomingMeds.length === 0) {
1021
+ emptyState.style.display = 'block';
1022
+ medicationList.style.display = 'none';
1023
+ } else {
1024
+ emptyState.style.display = 'none';
1025
+ medicationList.style.display = 'flex';
1026
+
1027
+ upcomingMeds.forEach((med, index) => {
1028
  const medItem = document.createElement('div');
1029
+ medItem.className = 'medication-item animate-on-scroll';
1030
  medItem.dataset.id = med.id;
1031
+ medItem.style.transitionDelay = `${index * 0.1}s`;
1032
 
1033
  const [hours, minutes] = med.time.split(':');
 
1034
  const hour = parseInt(hours);
1035
  const amPm = hour >= 12 ? 'PM' : 'AM';
1036
  const hour12 = hour % 12 || 12;
1037
+ const timeDisplay = `${hour12}:${minutes} ${amPm}`;
1038
+
1039
+ // Determine urgency color
1040
+ const now = new Date();
1041
+ const medTime = new Date();
1042
+ medTime.setHours(hour);
1043
+ medTime.setMinutes(minutes);
1044
+
1045
+ const timeDiff = (medTime - now) / (1000 * 60 * 60); // hours difference
1046
+ let urgencyClass = '';
1047
+
1048
+ if (timeDiff < 0) {
1049
+ // Past due
1050
+ urgencyClass = 'past-due';
1051
+ } else if (timeDiff < 1) {
1052
+ // Due soon (within 1 hour)
1053
+ urgencyClass = 'due-soon';
1054
+ }
1055
 
1056
  medItem.innerHTML = `
1057
  <div class="med-icon">
 
1059
  </div>
1060
  <div class="med-details">
1061
  <h3>${med.name}</h3>
1062
+ <p>${med.dosage} ${med.category || 'General'}</p>
1063
+ ${med.note ? `<div class="med-note"><i class="fas fa-info-circle"></i> ${med.note}</div>` : ''}
1064
  </div>
1065
+ <div class="med-time ${urgencyClass}">
1066
+ <p>${timeDisplay} ${urgencyClass === 'past-due' ? ' (Past Due)' : urgencyClass === 'due-soon' ? ' (Soon!)' : ''}</p>
1067
+ <button class="btn btn-success take-btn">
1068
+ <i class="fas fa-check"></i> Mark Taken
1069
  </button>
1070
  </div>
1071
  `;
1072
 
1073
+ if (urgencyClass === 'due-soon' || urgencyClass === 'past-due') {
1074
+ medItem.style.animation = urgencyClass === 'past-due' ? 'pulse 2s infinite' : 'pulse 3s infinite';
1075
+ }
1076
+
1077
  medicationList.appendChild(medItem);
1078
 
1079
  // Add event listener to the take button
1080
  medItem.querySelector('.take-btn').addEventListener('click', () => takeMedication(med.id));
1081
+ });
1082
+
1083
+ // Trigger animation when elements are in view
1084
+ setTimeout(() => {
1085
+ const observer = new IntersectionObserver((entries) => {
1086
+ entries.forEach(entry => {
1087
+ if (entry.isIntersecting) {
1088
+ entry.target.classList.add('show');
1089
+ }
1090
+ });
1091
+ }, { threshold: 0.1 });
1092
+
1093
+ document.querySelectorAll('.animate-on-scroll').forEach(el => {
1094
+ observer.observe(el);
1095
+ });
1096
+ }, 100);
1097
+ }
1098
  }
1099
 
1100
  // Mark medication as taken
 
1102
  const index = medications.findIndex(med => med.id === id);
1103
  if (index !== -1) {
1104
  medications[index].isTaken = true;
1105
+ medications[index].lastTaken = new Date().toISOString();
1106
  renderMedications();
1107
  updateStats();
1108
+ showNotification(`Marked ${medications[index].name} as taken.`, 'success');
1109
+
1110
+ // Cancel any scheduled notification for this medication
1111
+ if (scheduledNotifications[id]) {
1112
+ clearTimeout(scheduledNotifications[id]);
1113
+ delete scheduledNotifications[id];
1114
+ }
1115
 
1116
+ // Schedule notification for next dose if recurring
1117
+ if (notificationPermissionGranted) {
1118
+ scheduleSystemNotification(medications[index]);
1119
+ }
1120
  }
1121
  }
1122
 
1123
+ // Show notification with different types
1124
+ function showNotification(message, type = 'success') {
1125
+ // Show in-page notification
1126
+ notification.className = `notification ${type}`;
1127
  notificationText.textContent = message;
1128
  notification.classList.add('show');
1129
 
1130
  setTimeout(() => {
1131
  notification.classList.remove('show');
1132
  }, 3000);
1133
+
1134
+ // If permission granted and it's a warning/important notification, show system notification
1135
+ if (notificationPermissionGranted && (type === 'warning' || type === 'error')) {
1136
+ try {
1137
+ const notification = new Notification('MedTrack Alert', {
1138
+ body: message,
1139
+ icon: 'https://cdn-icons-png.flaticon.com/512/3161/3161837.png',
1140
+ });
1141
+
1142
+ setTimeout(() => notification.close(), 5000);
1143
+ } catch (e) {
1144
+ console.warn('Could not show system notification', e);
1145
+ }
1146
+ }
1147
  }
1148
 
1149
  // Check if any medications are due
 
1155
 
1156
  medications.forEach(med => {
1157
  if (!med.isTaken && med.time === currentTime) {
1158
+ const message = `Time to take ${med.name} (${med.dosage})${med.note ? ': ' + med.note : ''}`;
1159
+ showNotification(message, 'warning');
1160
+
1161
+ // If notifications are enabled, also show system notification
1162
+ if (notificationPermissionGranted) {
1163
+ try {
1164
+ const notification = new Notification(`Time to take ${med.name}`, {
1165
+ body: message,
1166
+ icon: 'https://cdn-icons-png.flaticon.com/512/3161/3161837.png',
1167
+ requireInteraction: true,
1168
+ vibrate: [200, 100, 200]
1169
+ });
1170
+
1171
+ // Auto-close after 5 minutes
1172
+ setTimeout(() => notification.close(), 5 * 60 * 1000);
1173
+ } catch (e) {
1174
+ console.warn('Could not show system notification', e);
1175
+ }
1176
+ }
1177
  }
1178
  });
1179
  }
 
1181
  // Schedule next notification for recurring medications
1182
  function scheduleNextNotification(medication) {
1183
  // In a real app, this would schedule an actual notification
1184
+ if (notificationPermissionGranted) {
1185
+ scheduleSystemNotification(medication);
1186
+ }
1187
  }
1188
 
1189
+ // Update statistics with animation
1190
  function updateStats() {
1191
  const total = medications.length;
1192
  const upcoming = medications.filter(med => !med.isTaken).length;
1193
  const taken = medications.filter(med => med.isTaken).length;
1194
  const adherence = total > 0 ? Math.round((taken / total) * 100) : 0;
1195
 
1196
+ // Animate count changes
1197
+ animateValue('upcomingCount', parseInt(upcomingCount.textContent), upcoming, 500);
1198
+ animateValue('totalMeds', parseInt(totalMeds.textContent), total, 500);
1199
+ animateValue('adherenceRate', parseInt(adherenceRate.textContent.replace('%', '')), adherence, 500);
1200
+ }
1201
+
1202
+ // Animate numeric value changes
1203
+ function animateValue(id, start, end, duration) {
1204
+ const obj = document.getElementById(id);
1205
+ let startTimestamp = null;
1206
+ const step = (timestamp) => {
1207
+ if (!startTimestamp) startTimestamp = timestamp;
1208
+ const progress = Math.min((timestamp - startTimestamp) / duration, 1);
1209
+ const val = Math.floor(progress * (end - start) + start);
1210
+ obj.textContent = id === 'adherenceRate' ? `${val}%` : val;
1211
+ if (progress < 1) {
1212
+ window.requestAnimationFrame(step);
1213
+ }
1214
+ };
1215
+ window.requestAnimationFrame(step);
1216
  }
1217
 
1218
+ // Show modal with animation
1219
  function showModal() {
1220
  addMedModal.style.display = 'flex';
1221
  document.body.style.overflow = 'hidden';
1222
+ setTimeout(() => addMedModal.classList.add('show'), 10);
1223
  }
1224
 
1225
+ // Hide modal with animation
1226
  function hideModal() {
1227
+ addMedModal.classList.remove('show');
1228
+ setTimeout(() => {
1229
+ addMedModal.style.display = 'none';
1230
+ document.body.style.overflow = 'auto';
1231
+ medicationForm.reset();
1232
+ while (timeInputs.children.length > 1) {
1233
+ timeInputs.removeChild(timeInputs.lastChild);
1234
+ }
1235
+ }, 300);
1236
  }
1237
 
1238
+ // Add new medication with additional fields
1239
  function addMedication(name, dosage, frequency, times, note) {
1240
+ const categories = ["Pain Relief", "Supplement", "Antibiotic", "Cardiac", "Gastrointestinal", "Other"];
1241
+ const randomCategory = categories[Math.floor(Math.random() * categories.length)];
1242
+
1243
  times.forEach(time => {
1244
  const newMed = {
1245
  id: nextId++,
 
1247
  dosage,
1248
  time,
1249
  isTaken: false,
1250
+ note,
1251
+ category: randomCategory,
1252
+ lastTaken: null
1253
  };
1254
 
1255
  medications.push(newMed);
1256
+
1257
+ // Schedule notification for this medication if permission granted
1258
+ if (notificationPermissionGranted) {
1259
+ scheduleSystemNotification(newMed);
1260
+ }
1261
  });
1262
 
1263
  renderMedications();
1264
  updateStats();
1265
+ showNotification(`Added ${name} to your medications.`, 'success');
1266
  hideModal();
1267
  }
1268
 
1269
+ // Setup intersection observer for scroll animations
1270
+ function setupIntersectionObserver() {
1271
+ const observer = new IntersectionObserver((entries) => {
1272
+ entries.forEach(entry => {
1273
+ if (entry.isIntersecting) {
1274
+ entry.target.classList.add('show');
1275
+ }
1276
+ });
1277
+ }, { threshold: 0.1 });
1278
+
1279
+ document.querySelectorAll('.animate-on-scroll').forEach(el => {
1280
+ observer.observe(el);
1281
+ });
1282
+ }
1283
+
1284
  // Event Listeners
1285
  addMedBtn.addEventListener('click', showModal);
1286
+ addFirstMed.addEventListener('click', showModal);
1287
  closeModal.addEventListener('click', hideModal);
1288
  cancelBtn.addEventListener('click', hideModal);
1289
 
 
1323
  });
1324
 
1325
  if (times.length === 0) {
1326
+ showNotification('Please enter at least one time', 'error');
1327
  return;
1328
  }
1329
 
1330
  addMedication(name, dosage, frequency, times, note);
1331
  });
1332
 
1333
+ // Close modal when clicking outside
1334
+ addMedModal.addEventListener('click', function(e) {
1335
+ if (e.target === addMedModal) {
1336
+ hideModal();
1337
+ }
1338
+ });
1339
+
1340
+ // Empty state button
1341
+ addFirstMed.addEventListener('click', showModal);
1342
+
1343
  // Initialize the app
1344
  init();
1345
 
1346
+ // Add pulse animation for emergencies
1347
+ const style = document.createElement('style');
1348
+ style.textContent = `
1349
+ @keyframes pulse {
1350
+ 0% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.4); }
1351
+ 70% { box-shadow: 0 0 0 10px rgba(231, 76, 60, 0); }
1352
+ 100% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0); }
1353
+ }
1354
+
1355
+ .due-soon p, .past-due p {
1356
+ color: #e74c3c !important;
1357
+ }
1358
+ `;
1359
+ document.head.appendChild(style);
1360
  </script>
1361
+ </body>
1362
  </html>