Digiator commited on
Commit
1c09ed6
·
verified ·
1 Parent(s): b67d9bf

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +238 -68
index.html CHANGED
@@ -207,7 +207,7 @@
207
  <i class="fas fa-chart-pie text-green-500 mr-2"></i> Life Balance
208
  </h3>
209
  <div class="flex justify-center">
210
- <div class="relative w-40 h-40">
211
  <div id="balance-chart" class="w-full h-full"></div>
212
  <div class="absolute inset-0 flex items-center justify-center">
213
  <div class="text-center">
@@ -336,7 +336,7 @@
336
  </div>
337
  <div class="mb-4">
338
  <label for="goal-title" class="block text-sm font-medium text-gray-700 mb-1">Goal Title</label>
339
- <input type="text" id="goal-title" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
340
  </div>
341
  <div class="mb-4">
342
  <label for="goal-description" class="block text-sm font-medium text-gray-700 mb-1">Description</label>
@@ -381,7 +381,7 @@
381
  <div class="bg-white rounded-lg shadow-xl max-w-md w-full mx-4 animate-fade-in">
382
  <div class="p-6">
383
  <div class="flex items-center mb-6">
384
- <div class="w-16 h-16 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 text-2xl mr-4">
385
  <i class="fas fa-user"></i>
386
  </div>
387
  <div>
@@ -391,7 +391,7 @@
391
  </div>
392
  <div class="space-y-4 mb-6">
393
  <div>
394
- <h4 class="text-sm font-semibound text-gray-700 mb-1">Categories</h4>
395
  <p class="text-gray-600" id="categories-count">0</p>
396
  </div>
397
  <div>
@@ -426,7 +426,7 @@
426
  <label class="block text-sm font-medium text-gray-700 mb-1">Your Data</label>
427
  <textarea id="export-data" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" rows="5" readonly></textarea>
428
  </div>
429
- <button id="download-export" class="w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-710 transition">
430
  <i class="fas fa-download mr-2"></i> Download Backup
431
  </button>
432
  </div>
@@ -507,7 +507,7 @@
507
  bgLight: 'bg-green-100',
508
  text: 'text-green-800',
509
  bg: 'bg-green-600',
510
- hover: 'hover:bg-green-710',
511
  border: 'border-green-500'
512
  },
513
  yellow: {
@@ -772,9 +772,9 @@
772
  <div class="flex justify-between">
773
  <h4 class="font-medium ${goal.completed ? 'text-gray-500 line-through' : 'text-gray-800'}">${goal.title}</h4>
774
  <div class="flex items-center space-x-2">
775
- <button class="edit-goal text-gray-400 hover:text-${category.color}-600" data-id="${goal.id}">
776
  <i class="fas fa-edit"></i>
777
- </button>
778
  <button class="toggle-goal text-${goal.completed ? 'gray-400' : category.color + '-600'}" data-id="${goal.id}">
779
  <i class="fas fa-${goal.completed ? 'undo' : 'check'}"></i>
780
  </button>
@@ -789,6 +789,31 @@
789
 
790
  goalsListContainer.appendChild(goalCard);
791
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
792
  }
793
 
794
  // Add "Add Goal" button at the bottom
@@ -802,31 +827,6 @@
802
 
803
  goalsListContainer.appendChild(addGoalButton);
804
 
805
- // Set up event listeners for the goal actions
806
- document.querySelectorAll('.edit-goal').forEach(btn => {
807
- btn.addEventListener('click', (e) => {
808
- e.stopPropagation();
809
- const goalId = btn.getAttribute('data-id');
810
- editGoal(goalId, categoryId);
811
- });
812
- });
813
-
814
- document.querySelectorAll('.toggle-goal').forEach(btn => {
815
- btn.addEventListener('click', (e) => {
816
- e.stopPropagation();
817
- const goalId = btn.getAttribute('data-id');
818
- toggleGoalCompletion(goalId);
819
- });
820
- });
821
-
822
- document.querySelectorAll('.delete-goal').forEach(btn => {
823
- btn.addEventListener('click', (e) => {
824
- e.stopPropagation();
825
- const goalId = btn.getAttribute('data-id');
826
- confirmDeleteGoal(goalId);
827
- });
828
- });
829
-
830
  showModal(viewGoalsModal);
831
  }
832
 
@@ -878,9 +878,9 @@
878
  <div class="flex justify-between">
879
  <h4 class="font-medium text-sm ${goal.completed ? 'text-gray-500 line-through' : 'text-gray-800'}">${goal.title}</h4>
880
  <div class="flex items-center space-x-2">
881
- <button class="edit-goal text-gray-400 hover:text-${category.color}-600" data-id="${goal.id}">
882
  <i class="fas fa-edit text-sm"></i>
883
- </button>
884
  <button class="toggle-goal text-${goal.completed ? 'gray-400' : category.color + '-600'}" data-id="${goal.id}">
885
  <i class="fas fa-${goal.completed ? 'undo' : 'check'} text-sm"></i>
886
  </button>
@@ -892,15 +892,21 @@
892
  ${goal.dueDate ? `<p class="text-xs mt-1 text-gray-500"><i class="fas fa-calendar-alt mr-1"></i> Due: ${formatDate(goal.dueDate)}</p>` : ''}
893
  `;
894
 
895
- goalCard.addEventListener('click', () => {
896
- // For small cards, just toggle completion on click
897
- toggleGoalCompletion(goal.id);
 
 
898
  });
899
 
900
- goalCard.querySelector('.edit-goal').addEventListener('click', (e) => {
901
- e.stopPropagation();
902
- editGoal(goal.id, categoryId);
903
- });
 
 
 
 
904
 
905
  goalCard.querySelector('.toggle-goal').addEventListener('click', (e) => {
906
  e.stopPropagation();
@@ -962,12 +968,10 @@
962
  document.getElementById('goal-description').value = '';
963
  document.getElementById('goal-due-date').value = '';
964
 
965
- // Reset the form event listener to add goal
966
- const form = document.getElementById('add-goal-form');
967
- form.removeEventListener('submit', handleUpdateGoalSubmit);
968
- form.addEventListener('submit', handleAddGoalSubmit);
969
 
970
- const submitBtn = form.querySelector('button[type="submit"]');
971
  submitBtn.textContent = 'Add Goal';
972
 
973
  showModal(addGoalModal);
@@ -1034,14 +1038,12 @@
1034
  document.getElementById('goal-due-date').value = goal.dueDate || '';
1035
 
1036
  // Change the form to edit mode
1037
- const form = document.getElementById('add-goal-form');
1038
- form.removeEventListener('submit', handleAddGoalSubmit);
1039
- form.addEventListener('submit', (e) => {
1040
  e.preventDefault();
1041
  updateGoal(goalId);
1042
- });
1043
 
1044
- const submitBtn = form.querySelector('button[type="submit"]');
1045
  submitBtn.textContent = 'Update Goal';
1046
 
1047
  showModal(addGoalModal);
@@ -1070,8 +1072,15 @@
1070
  closeModal(addGoalModal);
1071
 
1072
  // Refresh the goals view if it's open
1073
- if (viewGoalsModal.classList.contains('hidden')) return;
1074
- showAllGoals();
 
 
 
 
 
 
 
1075
  }
1076
 
1077
  // Toggle goal completion status
@@ -1101,8 +1110,15 @@
1101
  updateProfileStats();
1102
 
1103
  // Refresh the goals view if it's open
1104
- if (viewGoalsModal.classList.contains('hidden')) return;
1105
- viewGoalsForCategory(goal.categoryId);
 
 
 
 
 
 
 
1106
  }
1107
 
1108
  // Confirm deletion of a goal
@@ -1117,7 +1133,7 @@
1117
  confirmActionBtn.className = 'px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition';
1118
  confirmActionBtn.textContent = 'Delete';
1119
 
1120
- confirmActionBtn.onclick = () => {
1121
  deleteGoal(goalId);
1122
  closeModal(confirmModal);
1123
  };
@@ -1143,8 +1159,15 @@
1143
  updateProfileStats();
1144
 
1145
  // Refresh the goals view if it's open
1146
- if (viewGoalsModal.classList.contains('hidden')) return;
1147
- viewGoalsForCategory(deletedGoal.categoryId);
 
 
 
 
 
 
 
1148
  }
1149
 
1150
  // Confirm reset all data
@@ -1156,7 +1179,7 @@
1156
  confirmActionBtn.className = 'px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition';
1157
  confirmActionBtn.textContent = 'Reset Data';
1158
 
1159
- confirmActionBtn.onclick = () => {
1160
  resetAllData();
1161
  closeModal(confirmModal);
1162
  };
@@ -1288,16 +1311,18 @@
1288
 
1289
  let cumulativePercent = 0;
1290
  categoryProgress.forEach((cat, index) => {
1291
- const percent = (cat.progress / totalProgress) * 100;
1292
  if (percent <= 0) return;
1293
 
1294
- const startAngle = cumulativePercent * 3.6;
1295
  cumulativePercent += percent;
1296
- const endAngle = cumulativePercent * 3.6;
1297
 
 
1298
  const start = polarToCartesian(50, 50, 45, startAngle);
1299
  const end = polarToCartesian(50, 50, 45, endAngle);
1300
- const largeArcFlag = endAngle - startAngle <= 180 ? 0 : 1;
 
1301
 
1302
  const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
1303
  path.setAttribute("d", `M 50 50 L ${start.x} ${start.y} A 45 45 0 ${largeArcFlag} 1 ${end.x} ${end.y} Z`);
@@ -1308,6 +1333,14 @@
1308
  svg.appendChild(path);
1309
  });
1310
 
 
 
 
 
 
 
 
 
1311
  balanceChart.appendChild(svg);
1312
 
1313
  // Update the legend
@@ -1317,7 +1350,7 @@
1317
  legendItem.className = 'flex items-center text-xs';
1318
 
1319
  const colorSwatch = document.createElement('div');
1320
- colorSwatch.className = `w-3 h-3 rounded-full mr-2 bg-${cat.color}-500`;
1321
 
1322
  const progressText = document.createElement('span');
1323
  progressText.className = 'font-medium';
@@ -1372,11 +1405,31 @@
1372
  exportDataTextarea.value = dataStr;
1373
 
1374
  // Show export tab by default
1375
- exportTab.click();
1376
 
1377
  showModal(dataModal);
1378
  }
1379
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1380
  // Download exported data
1381
  function downloadExport() {
1382
  const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(appData, null, 2));
@@ -1411,7 +1464,7 @@
1411
  confirmActionBtn.className = 'px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition';
1412
  confirmActionBtn.textContent = 'Import';
1413
 
1414
- confirmActionBtn.onclick = () => {
1415
  appData = importedData;
1416
  saveData();
1417
 
@@ -1444,5 +1497,122 @@
1444
 
1445
  if (diffInSeconds < 60) return 'Just now';
1446
  if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)} minutes ago`;
1447
- if
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1448
  </html>
 
207
  <i class="fas fa-chart-pie text-green-500 mr-2"></i> Life Balance
208
  </h3>
209
  <div class="flex justify-center">
210
+ <div class="relative w-40 height-full">
211
  <div id="balance-chart" class="w-full h-full"></div>
212
  <div class="absolute inset-0 flex items-center justify-center">
213
  <div class="text-center">
 
336
  </div>
337
  <div class="mb-4">
338
  <label for="goal-title" class="block text-sm font-medium text-gray-700 mb-1">Goal Title</label>
339
+ ' <input type="text" id="goal-title" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
340
  </div>
341
  <div class="mb-4">
342
  <label for="goal-description" class="block text-sm font-medium text-gray-700 mb-1">Description</label>
 
381
  <div class="bg-white rounded-lg shadow-xl max-w-md w-full mx-4 animate-fade-in">
382
  <div class="p-6">
383
  <div class="flex items-center mb-6">
384
+ <div class="w-16 height-full rounded-full bg-blue-100 flex items-center justify-center text-blue-600 text-2xl mr-4">
385
  <i class="fas fa-user"></i>
386
  </div>
387
  <div>
 
391
  </div>
392
  <div class="space-y-4 mb-6">
393
  <div>
394
+ <h4 class="text-sm font-semibold text-gray-700 mb-1">Categories</h4>
395
  <p class="text-gray-600" id="categories-count">0</p>
396
  </div>
397
  <div>
 
426
  <label class="block text-sm font-medium text-gray-700 mb-1">Your Data</label>
427
  <textarea id="export-data" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" rows="5" readonly></textarea>
428
  </div>
429
+ <button id="download-export" class="w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition">
430
  <i class="fas fa-download mr-2"></i> Download Backup
431
  </button>
432
  </div>
 
507
  bgLight: 'bg-green-100',
508
  text: 'text-green-800',
509
  bg: 'bg-green-600',
510
+ hover: 'hover:bg-green-700',
511
  border: 'border-green-500'
512
  },
513
  yellow: {
 
772
  <div class="flex justify-between">
773
  <h4 class="font-medium ${goal.completed ? 'text-gray-500 line-through' : 'text-gray-800'}">${goal.title}</h4>
774
  <div class="flex items-center space-x-2">
775
+ ${!goal.completed ? `<button class="edit-goal text-gray-400 hover:text-${category.color}-600" data-id="${goal.id}">
776
  <i class="fas fa-edit"></i>
777
+ </button>` : ''}
778
  <button class="toggle-goal text-${goal.completed ? 'gray-400' : category.color + '-600'}" data-id="${goal.id}">
779
  <i class="fas fa-${goal.completed ? 'undo' : 'check'}"></i>
780
  </button>
 
789
 
790
  goalsListContainer.appendChild(goalCard);
791
  });
792
+
793
+ // Add event listeners for buttons
794
+ document.querySelectorAll('.edit-goal').forEach(btn => {
795
+ btn.addEventListener('click', (e) => {
796
+ e.stopPropagation();
797
+ const goalId = btn.getAttribute('data-id');
798
+ editGoal(goalId, categoryId);
799
+ });
800
+ });
801
+
802
+ document.querySelectorAll('.toggle-goal').forEach(btn => {
803
+ btn.addEventListener('click', (e) => {
804
+ e.stopPropagation();
805
+ const goalId = btn.getAttribute('data-id');
806
+ toggleGoalCompletion(goalId);
807
+ });
808
+ });
809
+
810
+ document.querySelectorAll('.delete-goal').forEach(btn => {
811
+ btn.addEventListener('click', (e) => {
812
+ e.stopPropagation();
813
+ const goalId = btn.getAttribute('data-id');
814
+ confirmDeleteGoal(goalId);
815
+ });
816
+ });
817
  }
818
 
819
  // Add "Add Goal" button at the bottom
 
827
 
828
  goalsListContainer.appendChild(addGoalButton);
829
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
830
  showModal(viewGoalsModal);
831
  }
832
 
 
878
  <div class="flex justify-between">
879
  <h4 class="font-medium text-sm ${goal.completed ? 'text-gray-500 line-through' : 'text-gray-800'}">${goal.title}</h4>
880
  <div class="flex items-center space-x-2">
881
+ ${!goal.completed ? `<button class="edit-goal text-gray-400 hover:text-${category.color}-600" data-id="${goal.id}">
882
  <i class="fas fa-edit text-sm"></i>
883
+ </button>` : ''}
884
  <button class="toggle-goal text-${goal.completed ? 'gray-400' : category.color + '-600'}" data-id="${goal.id}">
885
  <i class="fas fa-${goal.completed ? 'undo' : 'check'} text-sm"></i>
886
  </button>
 
892
  ${goal.dueDate ? `<p class="text-xs mt-1 text-gray-500"><i class="fas fa-calendar-alt mr-1"></i> Due: ${formatDate(goal.dueDate)}</p>` : ''}
893
  `;
894
 
895
+ goalCard.addEventListener('click', (e) => {
896
+ // If clicking directly on the card and not on a button, toggle completion
897
+ if (!e.target.closest('button')) {
898
+ toggleGoalCompletion(goal.id);
899
+ }
900
  });
901
 
902
+ // Add event listeners for buttons
903
+ const editBtn = goalCard.querySelector('.edit-goal');
904
+ if (editBtn) {
905
+ editBtn.addEventListener('click', (e) => {
906
+ e.stopPropagation();
907
+ editGoal(goal.id, categoryId);
908
+ });
909
+ }
910
 
911
  goalCard.querySelector('.toggle-goal').addEventListener('click', (e) => {
912
  e.stopPropagation();
 
968
  document.getElementById('goal-description').value = '';
969
  document.getElementById('goal-due-date').value = '';
970
 
971
+ // Reset the form to add goal mode
972
+ addGoalForm.onsubmit = handleAddGoalSubmit;
 
 
973
 
974
+ const submitBtn = addGoalForm.querySelector('button[type="submit"]');
975
  submitBtn.textContent = 'Add Goal';
976
 
977
  showModal(addGoalModal);
 
1038
  document.getElementById('goal-due-date').value = goal.dueDate || '';
1039
 
1040
  // Change the form to edit mode
1041
+ addGoalForm.onsubmit = function(e) {
 
 
1042
  e.preventDefault();
1043
  updateGoal(goalId);
1044
+ };
1045
 
1046
+ const submitBtn = addGoalForm.querySelector('button[type="submit"]');
1047
  submitBtn.textContent = 'Update Goal';
1048
 
1049
  showModal(addGoalModal);
 
1072
  closeModal(addGoalModal);
1073
 
1074
  // Refresh the goals view if it's open
1075
+ if (!viewGoalsModal.classList.contains('hidden')) {
1076
+ const goalsListContainer = document.getElementById('goals-list-container');
1077
+ const header = goalsListContainer.querySelector('h3');
1078
+ if (header && header.textContent.includes('All Goals')) {
1079
+ showAllGoals();
1080
+ } else {
1081
+ viewGoalsForCategory(goal.categoryId);
1082
+ }
1083
+ }
1084
  }
1085
 
1086
  // Toggle goal completion status
 
1110
  updateProfileStats();
1111
 
1112
  // Refresh the goals view if it's open
1113
+ if (!viewGoalsModal.classList.contains('hidden')) {
1114
+ const goalsListContainer = document.getElementById('goals-list-container');
1115
+ const header = goalsListContainer.querySelector('h3');
1116
+ if (header && header.textContent.includes('All Goals')) {
1117
+ showAllGoals();
1118
+ } else {
1119
+ viewGoalsForCategory(goal.categoryId);
1120
+ }
1121
+ }
1122
  }
1123
 
1124
  // Confirm deletion of a goal
 
1133
  confirmActionBtn.className = 'px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition';
1134
  confirmActionBtn.textContent = 'Delete';
1135
 
1136
+ confirmActionBtn.onclick = function() {
1137
  deleteGoal(goalId);
1138
  closeModal(confirmModal);
1139
  };
 
1159
  updateProfileStats();
1160
 
1161
  // Refresh the goals view if it's open
1162
+ if (!viewGoalsModal.classList.contains('hidden')) {
1163
+ const goalsListContainer = document.getElementById('goals-list-container');
1164
+ const header = goalsListContainer.querySelector('h3');
1165
+ if (header && header.textContent.includes('All Goals')) {
1166
+ showAllGoals();
1167
+ } else {
1168
+ viewGoalsForCategory(deletedGoal.categoryId);
1169
+ }
1170
+ }
1171
  }
1172
 
1173
  // Confirm reset all data
 
1179
  confirmActionBtn.className = 'px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition';
1180
  confirmActionBtn.textContent = 'Reset Data';
1181
 
1182
+ confirmActionBtn.onclick = function() {
1183
  resetAllData();
1184
  closeModal(confirmModal);
1185
  };
 
1311
 
1312
  let cumulativePercent = 0;
1313
  categoryProgress.forEach((cat, index) => {
1314
+ const percent = (cat.progress / 100) * 360; // Convert to degrees
1315
  if (percent <= 0) return;
1316
 
1317
+ const startAngle = cumulativePercent;
1318
  cumulativePercent += percent;
1319
+ const endAngle = cumulativePercent;
1320
 
1321
+ // Create path for each segment
1322
  const start = polarToCartesian(50, 50, 45, startAngle);
1323
  const end = polarToCartesian(50, 50, 45, endAngle);
1324
+
1325
+ const largeArcFlag = percent > 180 ? 1 : 0;
1326
 
1327
  const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
1328
  path.setAttribute("d", `M 50 50 L ${start.x} ${start.y} A 45 45 0 ${largeArcFlag} 1 ${end.x} ${end.y} Z`);
 
1333
  svg.appendChild(path);
1334
  });
1335
 
1336
+ // Add white circle in the center
1337
+ const centerCircle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
1338
+ centerCircle.setAttribute("cx", "50");
1339
+ centerCircle.setAttribute("cy", "50");
1340
+ centerCircle.setAttribute("r", "20");
1341
+ centerCircle.setAttribute("fill", "#fff");
1342
+ svg.appendChild(centerCircle);
1343
+
1344
  balanceChart.appendChild(svg);
1345
 
1346
  // Update the legend
 
1350
  legendItem.className = 'flex items-center text-xs';
1351
 
1352
  const colorSwatch = document.createElement('div');
1353
+ colorSwatch.className = `w-3 h-3 rounded-full mr-2 bg-${cat.color}-600`;
1354
 
1355
  const progressText = document.createElement('span');
1356
  progressText.className = 'font-medium';
 
1405
  exportDataTextarea.value = dataStr;
1406
 
1407
  // Show export tab by default
1408
+ showExportTab();
1409
 
1410
  showModal(dataModal);
1411
  }
1412
 
1413
+ // Show export tab
1414
+ function showExportTab() {
1415
+ exportContent.classList.remove('hidden');
1416
+ importContent.classList.add('hidden');
1417
+ exportTab.classList.add('border-b-2', 'border-blue-600', 'text-blue-600');
1418
+ exportTab.classList.remove('text-gray-500');
1419
+ importTab.classList.remove('border-b-2', 'border-blue-600', 'text-blue-600');
1420
+ importTab.classList.add('text-gray-500');
1421
+ }
1422
+
1423
+ // Show import tab
1424
+ function showImportTab() {
1425
+ importContent.classList.remove('hidden');
1426
+ exportContent.classList.add('hidden');
1427
+ importTab.classList.add('border-b-2', 'border-blue-600', 'text-blue-600');
1428
+ importTab.classList.remove('text-gray-500');
1429
+ exportTab.classList.remove('border-b-2', 'border-blue-600', 'text-blue-600');
1430
+ exportTab.classList.add('text-gray-500');
1431
+ }
1432
+
1433
  // Download exported data
1434
  function downloadExport() {
1435
  const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(appData, null, 2));
 
1464
  confirmActionBtn.className = 'px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition';
1465
  confirmActionBtn.textContent = 'Import';
1466
 
1467
+ confirmActionBtn.onclick = function() {
1468
  appData = importedData;
1469
  saveData();
1470
 
 
1497
 
1498
  if (diffInSeconds < 60) return 'Just now';
1499
  if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)} minutes ago`;
1500
+ if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)} hours ago`;
1501
+ if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)} days ago`;
1502
+ if (diffInSeconds < 2592000) return `${Math.floor(diffInSeconds / 604800)} weeks ago`;
1503
+ if (diffInSeconds < 31536000) return `${Math.floor(diffInSeconds / 2592000)} months ago`;
1504
+ return `${Math.floor(diffInSeconds / 31536000)} years ago`;
1505
+ }
1506
+
1507
+ // Show modal
1508
+ function showModal(modal) {
1509
+ modal.classList.remove('hidden');
1510
+ modal.classList.add('flex');
1511
+ }
1512
+
1513
+ // Close modal
1514
+ function closeModal(modal) {
1515
+ modal.classList.add('hidden');
1516
+ modal.classList.remove('flex');
1517
+ }
1518
+
1519
+ // Add category form handler
1520
+ function handleAddCategorySubmit(e) {
1521
+ e.preventDefault();
1522
+ const name = document.getElementById('category-name').value.trim();
1523
+ const icon = document.getElementById('category-icon').value;
1524
+ const color = document.getElementById('category-color').value;
1525
+
1526
+ if (!name) {
1527
+ alert('Please enter a category name');
1528
+ return;
1529
+ }
1530
+
1531
+ addCategory(name, icon, color);
1532
+ }
1533
+
1534
+ // Add goal form handler
1535
+ function handleAddGoalSubmit(e) {
1536
+ e.preventDefault();
1537
+ const categoryId = document.getElementById('goal-category').value;
1538
+ const title = document.getElementById('goal-title').value.trim();
1539
+ const description = document.getElementById('goal-description').value.trim();
1540
+ const dueDate = document.getElementById('goal-due-date').value || null;
1541
+
1542
+ if (!title) {
1543
+ alert('Please enter a goal title');
1544
+ return;
1545
+ }
1546
+
1547
+ addGoal(categoryId, title, description, dueDate);
1548
+ }
1549
+
1550
+ // Event listeners
1551
+ document.addEventListener('DOMContentLoaded', function() {
1552
+ // Initialize the app
1553
+ initApp();
1554
+
1555
+ // Add form submit handlers
1556
+ addCategoryForm.addEventListener('submit', handleAddCategorySubmit);
1557
+ addGoalForm.addEventListener('submit', handleAddGoalSubmit);
1558
+
1559
+ // Button click handlers
1560
+ addCategoryBtn.addEventListener('click', showAddCategoryModal);
1561
+ viewAllBtn.addEventListener('click', showAllGoals);
1562
+ quickAddGoal.addEventListener('click', showAddGoalModal);
1563
+ quickViewTasks.addEventListener('click', showAllGoals);
1564
+ quickViewProgress.addEventListener('click', showAllGoals);
1565
+ quickViewCalendar.addEventListener('click', showAllGoals);
1566
+ profileBtn.addEventListener('click', function() {
1567
+ updateProfileStats();
1568
+ showModal(profileModal);
1569
+ });
1570
+ exportBtn.addEventListener('click', exportData);
1571
+ importBtn.addEventListener('click', function() {
1572
+ showModal(dataModal);
1573
+ showImportTab();
1574
+ });
1575
+ fab.addEventListener('click', function() {
1576
+ showAddGoalModal();
1577
+ });
1578
+ resetDataBtn.addEventListener('click', confirmResetData);
1579
+ backupDataBtn.addEventListener('click', exportData);
1580
+
1581
+ // Modal close buttons
1582
+ document.getElementById('cancel-add-category').addEventListener('click', function() {
1583
+ closeModal(addCategoryModal);
1584
+ });
1585
+ document.getElementById('cancel-add-goal').addEventListener('click', function() {
1586
+ closeModal(addGoalModal);
1587
+ });
1588
+ document.getElementById('close-view-goals').addEventListener('click', function() {
1589
+ closeModal(viewGoalsModal);
1590
+ });
1591
+ document.getElementById('close-profile').addEventListener('click', function() {
1592
+ closeModal(profileModal);
1593
+ });
1594
+ document.getElementById('confirm-cancel').addEventListener('click', function() {
1595
+ closeModal(confirmModal);
1596
+ });
1597
+ document.getElementById('cancel-import').addEventListener('click', function() {
1598
+ closeModal(dataModal);
1599
+ });
1600
+
1601
+ // Data modal tabs
1602
+ exportTab.addEventListener('click', showExportTab);
1603
+ importTab.addEventListener('click', showImportTab);
1604
+
1605
+ // Data modal buttons
1606
+ document.getElementById('download-export').addEventListener('click', downloadExport);
1607
+ document.getElementById('confirm-import').addEventListener('click', function() {
1608
+ const file = importFileInput.files[0];
1609
+ if (!file) {
1610
+ alert('Please select a file to import');
1611
+ return;
1612
+ }
1613
+ importData(file);
1614
+ });
1615
+ });
1616
+ </script>
1617
+ </body>
1618
  </html>