Add 2 files
Browse files- index.html +426 -766
- prompts.txt +3 -1
index.html
CHANGED
|
@@ -3,850 +3,510 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
-
<title>Job Application Tracker
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
| 9 |
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
|
| 10 |
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"></script>
|
| 11 |
<style>
|
| 12 |
-
.
|
| 13 |
-
|
| 14 |
-
}
|
| 15 |
-
@keyframes fadeIn {
|
| 16 |
-
from { opacity: 0; transform: translateY(10px); }
|
| 17 |
-
to { opacity: 1; transform: translateY(0); }
|
| 18 |
-
}
|
| 19 |
-
.pulse {
|
| 20 |
-
animation: pulse 1s infinite;
|
| 21 |
-
}
|
| 22 |
-
@keyframes pulse {
|
| 23 |
-
0% { transform: scale(1); }
|
| 24 |
-
50% { transform: scale(1.05); }
|
| 25 |
-
100% { transform: scale(1); }
|
| 26 |
-
}
|
| 27 |
-
.modal {
|
| 28 |
-
transition: opacity 0.3s ease;
|
| 29 |
-
}
|
| 30 |
-
.modal-overlay {
|
| 31 |
-
background-color: rgba(0, 0, 0, 0.5);
|
| 32 |
}
|
| 33 |
.chart-bar {
|
| 34 |
-
transition: height 0.5s ease-out;
|
| 35 |
-
}
|
| 36 |
-
.progress-ring__circle {
|
| 37 |
-
transition: stroke-dashoffset 0.5s ease-out;
|
| 38 |
-
transform: rotate(-90deg);
|
| 39 |
-
transform-origin: 50% 50%;
|
| 40 |
-
}
|
| 41 |
-
.glow {
|
| 42 |
-
box-shadow: 0 0 15px rgba(99, 102, 241, 0.5);
|
| 43 |
}
|
| 44 |
</style>
|
| 45 |
</head>
|
| 46 |
-
<body class="bg-
|
| 47 |
<div class="container mx-auto px-4 py-8 max-w-4xl">
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
<
|
|
|
|
| 51 |
</header>
|
| 52 |
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
<
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
| 63 |
</div>
|
| 64 |
</div>
|
| 65 |
-
<div class="flex
|
| 66 |
-
<
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
fill="transparent"
|
| 73 |
-
r="36"
|
| 74 |
-
cx="40"
|
| 75 |
-
cy="40"
|
| 76 |
-
/>
|
| 77 |
-
<circle
|
| 78 |
-
class="progress-ring__circle text-indigo-600"
|
| 79 |
-
stroke-width="8"
|
| 80 |
-
stroke-linecap="round"
|
| 81 |
-
stroke="currentColor"
|
| 82 |
-
fill="transparent"
|
| 83 |
-
r="36"
|
| 84 |
-
cx="40"
|
| 85 |
-
cy="40"
|
| 86 |
-
id="progress-ring"
|
| 87 |
-
/>
|
| 88 |
-
</svg>
|
| 89 |
-
<div class="absolute inset-0 flex items-center justify-center">
|
| 90 |
-
<span class="text-2xl font-bold text-indigo-800" id="today-count">0</span>
|
| 91 |
-
</div>
|
| 92 |
-
</div>
|
| 93 |
-
<div class="flex flex-col space-y-2">
|
| 94 |
-
<div class="flex space-x-2">
|
| 95 |
-
<button id="decrease-btn" class="bg-red-500 hover:bg-red-600 text-white rounded-full w-12 h-12 flex items-center justify-center shadow-md transition-all transform hover:scale-105">
|
| 96 |
-
<i class="fas fa-minus text-lg"></i>
|
| 97 |
-
</button>
|
| 98 |
-
<button id="add-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white rounded-full w-12 h-12 flex items-center justify-center shadow-md transition-all transform hover:scale-105">
|
| 99 |
-
<i class="fas fa-plus text-lg"></i>
|
| 100 |
-
</button>
|
| 101 |
-
</div>
|
| 102 |
-
<button id="add-custom-btn" class="bg-indigo-100 hover:bg-indigo-200 text-indigo-700 rounded-full w-full h-8 flex items-center justify-center shadow-md text-sm transition-all">
|
| 103 |
-
<i class="fas fa-calendar-day mr-1"></i> Custom Date
|
| 104 |
</button>
|
| 105 |
</div>
|
| 106 |
</div>
|
| 107 |
</div>
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
<
|
| 111 |
-
<h3 class="font-medium text-gray-700">Total Applications</h3>
|
| 112 |
-
<span class="text-xl font-bold text-indigo-800" id="total-count">0</span>
|
| 113 |
-
</div>
|
| 114 |
-
<div class="w-full bg-gray-200 rounded-full h-2.5">
|
| 115 |
-
<div id="total-progress" class="bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
|
| 116 |
-
</div>
|
| 117 |
-
</div>
|
| 118 |
-
</div>
|
| 119 |
-
|
| 120 |
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
| 121 |
-
<div class="bg-white rounded-xl shadow-lg p-6">
|
| 122 |
-
<h2 class="text-xl font-semibold text-gray-800 mb-4">Weekly Overview</h2>
|
| 123 |
-
<div class="flex justify-between items-end h-40 mt-6">
|
| 124 |
-
<!-- Weekly chart bars will be added here -->
|
| 125 |
-
</div>
|
| 126 |
-
</div>
|
| 127 |
-
<div class="bg-white rounded-xl shadow-lg p-6">
|
| 128 |
-
<h2 class="text-xl font-semibold text-gray-800 mb-4">Monthly Progress</h2>
|
| 129 |
-
<div class="flex justify-center">
|
| 130 |
-
<div id="monthly-chart" class="w-full h-40">
|
| 131 |
-
<!-- Monthly chart will be added here -->
|
| 132 |
-
</div>
|
| 133 |
-
</div>
|
| 134 |
</div>
|
| 135 |
</div>
|
| 136 |
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
<div class="flex space-x-2">
|
| 141 |
-
<button id="settings-btn" class="text-indigo-600 hover:text-indigo-800 flex items-center">
|
| 142 |
-
<i class="fas fa-cog mr-1"></i>
|
| 143 |
-
<span>Settings</span>
|
| 144 |
-
</button>
|
| 145 |
-
</div>
|
| 146 |
-
</div>
|
| 147 |
-
|
| 148 |
-
<div id="history-list" class="space-y-3">
|
| 149 |
-
<div class="text-center py-8 text-gray-400" id="empty-state">
|
| 150 |
-
<i class="fas fa-clipboard-list text-4xl mb-2"></i>
|
| 151 |
-
<p>No applications recorded yet</p>
|
| 152 |
-
<button id="get-started-btn" class="mt-4 px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-md">
|
| 153 |
-
Add Your First Application
|
| 154 |
-
</button>
|
| 155 |
-
</div>
|
| 156 |
-
<!-- History items will be added here dynamically -->
|
| 157 |
-
</div>
|
| 158 |
-
</div>
|
| 159 |
-
|
| 160 |
-
<div class="mt-6 text-center text-sm text-gray-500">
|
| 161 |
-
<p>Every application is a step closer to your dream job. Keep going!</p>
|
| 162 |
-
</div>
|
| 163 |
-
</div>
|
| 164 |
-
|
| 165 |
-
<!-- Modal for custom date entry -->
|
| 166 |
-
<div id="date-modal" class="fixed inset-0 flex items-center justify-center z-50 modal opacity-0 pointer-events-none">
|
| 167 |
-
<div class="modal-overlay absolute inset-0"></div>
|
| 168 |
-
<div class="bg-white rounded-xl shadow-xl p-6 z-10 w-full max-w-md transform transition-all scale-95">
|
| 169 |
-
<div class="flex justify-between items-center mb-4">
|
| 170 |
-
<h3 class="text-xl font-semibold text-gray-800">Add/Edit Applications</h3>
|
| 171 |
-
<button id="close-modal" class="text-gray-500 hover:text-gray-700">
|
| 172 |
-
<i class="fas fa-times"></i>
|
| 173 |
-
</button>
|
| 174 |
-
</div>
|
| 175 |
-
<div class="mb-4">
|
| 176 |
-
<label for="custom-date" class="block text-sm font-medium text-gray-700 mb-1">Select Date</label>
|
| 177 |
-
<input type="date" id="custom-date" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
| 178 |
-
</div>
|
| 179 |
<div class="mb-4">
|
| 180 |
-
<
|
| 181 |
-
|
| 182 |
-
<
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
<
|
| 186 |
-
<button id="increase-custom" class="bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-r-md w-10 h-10 flex items-center justify-center">
|
| 187 |
-
<i class="fas fa-plus"></i>
|
| 188 |
-
</button>
|
| 189 |
</div>
|
| 190 |
</div>
|
| 191 |
-
<div class="mb-4">
|
| 192 |
-
<
|
| 193 |
-
|
| 194 |
-
</div>
|
| 195 |
-
<div class="flex justify-end space-x-3">
|
| 196 |
-
<button id="delete-entry" class="px-4 py-2 text-red-600 hover:text-red-800 hidden">
|
| 197 |
-
<i class="fas fa-trash mr-1"></i> Delete
|
| 198 |
-
</button>
|
| 199 |
-
<button id="cancel-modal" class="px-4 py-2 text-gray-600 hover:text-gray-800">
|
| 200 |
-
Cancel
|
| 201 |
</button>
|
| 202 |
-
<
|
| 203 |
-
|
|
|
|
| 204 |
</button>
|
| 205 |
</div>
|
|
|
|
|
|
|
|
|
|
| 206 |
</div>
|
| 207 |
-
</div>
|
| 208 |
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
<h3 class="text-xl font-semibold text-gray-800">Settings</h3>
|
| 215 |
-
<button id="close-settings" class="text-gray-500 hover:text-gray-700">
|
| 216 |
-
<i class="fas fa-times"></i>
|
| 217 |
-
</button>
|
| 218 |
</div>
|
| 219 |
-
<div class="
|
| 220 |
-
<
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
<button data-theme="indigo" class="theme-btn w-8 h-8 rounded-full bg-indigo-600 border-2 border-indigo-800"></button>
|
| 234 |
-
<button data-theme="emerald" class="theme-btn w-8 h-8 rounded-full bg-emerald-600 border-2 border-transparent"></button>
|
| 235 |
-
<button data-theme="rose" class="theme-btn w-8 h-8 rounded-full bg-rose-600 border-2 border-transparent"></button>
|
| 236 |
-
<button data-theme="violet" class="theme-btn w-8 h-8 rounded-full bg-violet-600 border-2 border-transparent"></button>
|
| 237 |
-
<button data-theme="sky" class="theme-btn w-8 h-8 rounded-full bg-sky-600 border-2 border-transparent"></button>
|
| 238 |
-
</div>
|
| 239 |
</div>
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
</div>
|
| 248 |
</div>
|
| 249 |
</div>
|
| 250 |
|
| 251 |
<script>
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
|
| 267 |
-
//
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
|
|
|
|
|
|
| 278 |
|
| 279 |
-
//
|
| 280 |
-
const
|
| 281 |
-
const
|
| 282 |
-
const closeSettings = document.getElementById('close-settings');
|
| 283 |
-
const cancelSettings = document.getElementById('cancel-settings');
|
| 284 |
-
const saveSettings = document.getElementById('save-settings');
|
| 285 |
-
const timezoneSelect = document.getElementById('timezone-select');
|
| 286 |
-
const dailyGoalInput = document.getElementById('daily-goal');
|
| 287 |
-
const themeButtons = document.querySelectorAll('.theme-btn');
|
| 288 |
|
| 289 |
-
//
|
| 290 |
-
|
| 291 |
-
timezone: 'manual',
|
| 292 |
-
dailyGoal: 5,
|
| 293 |
-
theme: 'indigo'
|
| 294 |
-
};
|
| 295 |
|
| 296 |
-
//
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
sky: { primary: 'sky', secondary: 'cyan' }
|
| 304 |
-
};
|
| 305 |
-
|
| 306 |
-
const colorSet = colors[theme] || colors.indigo;
|
| 307 |
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
});
|
| 312 |
|
| 313 |
-
document.
|
| 314 |
-
|
| 315 |
-
|
| 316 |
|
| 317 |
-
document.
|
| 318 |
-
|
| 319 |
-
|
| 320 |
|
| 321 |
-
document.
|
| 322 |
-
|
| 323 |
-
});
|
| 324 |
|
| 325 |
-
document.
|
| 326 |
-
|
| 327 |
-
|
|
|
|
|
|
|
| 328 |
|
| 329 |
-
|
| 330 |
-
if (totalProgress) {
|
| 331 |
-
totalProgress.className = totalProgress.className.replace(/bg-indigo-\d+/g, `bg-${colorSet.primary}-600`);
|
| 332 |
-
}
|
| 333 |
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
} else {
|
| 339 |
-
btn.classList.replace(`border-${colorSet.primary}-800`, 'border-transparent');
|
| 340 |
-
}
|
| 341 |
-
});
|
| 342 |
-
}
|
| 343 |
-
|
| 344 |
-
// Apply saved theme
|
| 345 |
-
applyTheme(userSettings.theme);
|
| 346 |
-
|
| 347 |
-
// Populate timezone dropdown
|
| 348 |
-
function populateTimezones() {
|
| 349 |
-
const timezones = moment.tz.names();
|
| 350 |
-
timezoneSelect.innerHTML = '<option value="auto">Auto-detect</option>';
|
| 351 |
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
};
|
| 408 |
|
| 409 |
-
|
| 410 |
-
let todayEntry = appData.history.find(entry => entry.date === todayKey);
|
| 411 |
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
}
|
| 417 |
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
renderHistory();
|
| 421 |
-
renderCharts();
|
| 422 |
-
|
| 423 |
-
// Update progress ring
|
| 424 |
-
function updateProgressRing() {
|
| 425 |
-
const radius = 36;
|
| 426 |
-
const circumference = radius * 2 * Math.PI;
|
| 427 |
-
const progress = (todayEntry.count / userSettings.dailyGoal) * 100;
|
| 428 |
-
const offset = circumference - (progress / 100) * circumference;
|
| 429 |
|
| 430 |
-
|
| 431 |
-
|
|
|
|
| 432 |
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
todayEntry.count++;
|
| 443 |
-
appData.total++;
|
| 444 |
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
setTimeout(() => this.classList.remove('pulse'), 1000);
|
| 448 |
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
renderHistory();
|
| 452 |
-
renderCharts();
|
| 453 |
-
});
|
| 454 |
-
|
| 455 |
-
// Decrease button click handler
|
| 456 |
-
decreaseBtn.addEventListener('click', function() {
|
| 457 |
-
if (todayEntry.count > 0) {
|
| 458 |
-
todayEntry.count--;
|
| 459 |
-
appData.total--;
|
| 460 |
-
|
| 461 |
-
saveData();
|
| 462 |
-
updateCounts();
|
| 463 |
-
renderHistory();
|
| 464 |
-
renderCharts();
|
| 465 |
-
}
|
| 466 |
-
});
|
| 467 |
-
|
| 468 |
-
// Add custom date button click handler
|
| 469 |
-
addCustomBtn.addEventListener('click', function() {
|
| 470 |
-
// Reset modal values
|
| 471 |
-
customDate.value = todayKey;
|
| 472 |
-
customCount.value = 1;
|
| 473 |
-
customNotes.value = '';
|
| 474 |
-
deleteEntryBtn.classList.add('hidden');
|
| 475 |
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
});
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
setTimeout(() => {
|
| 499 |
-
dateModal.classList.remove('opacity-100', 'pointer-events-auto');
|
| 500 |
-
dateModal.classList.add('opacity-0', 'pointer-events-none');
|
| 501 |
-
}, 200);
|
| 502 |
}
|
| 503 |
|
| 504 |
-
|
| 505 |
-
|
| 506 |
|
| 507 |
-
//
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
settingsModal.classList.add('opacity-100', 'pointer-events-auto');
|
| 511 |
-
setTimeout(() => {
|
| 512 |
-
settingsModal.querySelector('.z-10').classList.remove('scale-95');
|
| 513 |
-
settingsModal.querySelector('.z-10').classList.add('scale-100');
|
| 514 |
-
}, 10);
|
| 515 |
}
|
| 516 |
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
}
|
| 525 |
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
userSettings.dailyGoal = parseInt(dailyGoalInput.value);
|
| 534 |
-
|
| 535 |
-
// Find and apply selected theme
|
| 536 |
-
themeButtons.forEach(btn => {
|
| 537 |
-
if (btn.classList.contains('border-indigo-800') ||
|
| 538 |
-
btn.classList.contains('border-emerald-800') ||
|
| 539 |
-
btn.classList.contains('border-rose-800') ||
|
| 540 |
-
btn.classList.contains('border-violet-800') ||
|
| 541 |
-
btn.classList.contains('border-sky-800')) {
|
| 542 |
-
userSettings.theme = btn.dataset.theme;
|
| 543 |
-
}
|
| 544 |
-
});
|
| 545 |
-
|
| 546 |
-
localStorage.setItem('jobAppSettings', JSON.stringify(userSettings));
|
| 547 |
-
applyTheme(userSettings.theme);
|
| 548 |
-
displayTimezone();
|
| 549 |
-
closeSettingsHandler();
|
| 550 |
-
|
| 551 |
-
// Update today's date if timezone changed
|
| 552 |
-
const newTodayKey = getCurrentDate();
|
| 553 |
-
if (newTodayKey !== todayKey) {
|
| 554 |
-
// Need to handle timezone change - this would require more complex logic
|
| 555 |
-
// For now, we'll just refresh the display
|
| 556 |
-
location.reload();
|
| 557 |
-
}
|
| 558 |
-
});
|
| 559 |
-
|
| 560 |
-
// Theme selection
|
| 561 |
-
themeButtons.forEach(btn => {
|
| 562 |
-
btn.addEventListener('click', function() {
|
| 563 |
-
themeButtons.forEach(b => {
|
| 564 |
-
b.classList.replace(/border-\w+-800/g, 'border-transparent');
|
| 565 |
-
});
|
| 566 |
-
|
| 567 |
-
const theme = this.dataset.theme;
|
| 568 |
-
const colorSet = {
|
| 569 |
-
indigo: 'indigo',
|
| 570 |
-
emerald: 'emerald',
|
| 571 |
-
rose: 'rose',
|
| 572 |
-
violet: 'violet',
|
| 573 |
-
sky: 'sky'
|
| 574 |
-
}[theme];
|
| 575 |
-
|
| 576 |
-
this.classList.replace('border-transparent', `border-${colorSet}-800`);
|
| 577 |
-
});
|
| 578 |
-
});
|
| 579 |
|
| 580 |
-
//
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 590 |
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
if (
|
| 598 |
-
|
| 599 |
-
|
| 600 |
-
|
| 601 |
-
|
| 602 |
-
// Find or create entry for selected date
|
| 603 |
-
let entry = appData.history.find(entry => entry.date === selectedDate);
|
| 604 |
-
|
| 605 |
-
if (entry) {
|
| 606 |
-
// Calculate the difference to update total correctly
|
| 607 |
-
const diff = count - (entry.count || 0);
|
| 608 |
-
entry.count = count;
|
| 609 |
-
entry.notes = notes;
|
| 610 |
-
appData.total += diff;
|
| 611 |
} else {
|
| 612 |
-
|
| 613 |
-
entry = { date: selectedDate, count: count, notes: notes };
|
| 614 |
-
appData.history.unshift(entry);
|
| 615 |
-
appData.total += count;
|
| 616 |
-
}
|
| 617 |
-
|
| 618 |
-
// If this is today's entry, update todayEntry reference
|
| 619 |
-
if (selectedDate === todayKey) {
|
| 620 |
-
todayEntry = entry;
|
| 621 |
}
|
| 622 |
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
renderHistory();
|
| 626 |
-
renderCharts();
|
| 627 |
-
closeModalHandler();
|
| 628 |
-
});
|
| 629 |
-
|
| 630 |
-
// Delete entry
|
| 631 |
-
deleteEntryBtn.addEventListener('click', function() {
|
| 632 |
-
const selectedDate = customDate.value;
|
| 633 |
-
const entryIndex = appData.history.findIndex(entry => entry.date === selectedDate);
|
| 634 |
-
|
| 635 |
-
if (entryIndex !== -1) {
|
| 636 |
-
const entry = appData.history[entryIndex];
|
| 637 |
-
appData.total -= entry.count;
|
| 638 |
-
appData.history.splice(entryIndex, 1);
|
| 639 |
-
|
| 640 |
-
saveData();
|
| 641 |
-
updateCounts();
|
| 642 |
-
renderHistory();
|
| 643 |
-
renderCharts();
|
| 644 |
-
closeModalHandler();
|
| 645 |
-
}
|
| 646 |
-
});
|
| 647 |
-
|
| 648 |
-
// Update count displays
|
| 649 |
-
function updateCounts() {
|
| 650 |
-
todayCountEl.textContent = todayEntry.count;
|
| 651 |
-
totalCountEl.textContent = appData.total;
|
| 652 |
-
|
| 653 |
-
// Update progress ring
|
| 654 |
-
updateProgressRing();
|
| 655 |
-
|
| 656 |
-
// Update total progress (simple visualization)
|
| 657 |
-
const maxTotal = 100; // Just for visualization purposes
|
| 658 |
-
const progressPercent = Math.min((appData.total / maxTotal) * 100, 100);
|
| 659 |
-
totalProgress.style.width = `${progressPercent}%`;
|
| 660 |
-
|
| 661 |
-
// Add animation when count changes
|
| 662 |
-
todayCountEl.classList.add('fade-in');
|
| 663 |
-
totalCountEl.classList.add('fade-in');
|
| 664 |
-
setTimeout(() => {
|
| 665 |
-
todayCountEl.classList.remove('fade-in');
|
| 666 |
-
totalCountEl.classList.remove('fade-in');
|
| 667 |
-
}, 300);
|
| 668 |
}
|
| 669 |
|
| 670 |
-
|
| 671 |
-
|
| 672 |
-
|
| 673 |
-
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
|
| 683 |
-
|
| 684 |
-
|
| 685 |
-
|
| 686 |
-
|
| 687 |
-
|
| 688 |
-
|
| 689 |
-
let formattedEntryDate;
|
| 690 |
-
if (userSettings.timezone === 'auto') {
|
| 691 |
-
formattedEntryDate = moment(entry.date).format('ddd, MMM D, YYYY');
|
| 692 |
-
} else {
|
| 693 |
-
formattedEntryDate = moment.tz(entry.date, userSettings.timezone).format('ddd, MMM D, YYYY');
|
| 694 |
-
}
|
| 695 |
-
|
| 696 |
-
const historyItem = document.createElement('div');
|
| 697 |
-
historyItem.className = 'flex justify-between items-center p-3 bg-gray-50 rounded-lg fade-in hover:bg-gray-100 cursor-pointer transition-colors';
|
| 698 |
-
if (isToday) {
|
| 699 |
-
historyItem.classList.add('border-l-4', `border-${userSettings.theme}-500`);
|
| 700 |
-
}
|
| 701 |
-
|
| 702 |
-
historyItem.innerHTML = `
|
| 703 |
-
<div class="flex items-center">
|
| 704 |
-
<div class="w-10 h-10 rounded-full bg-${userSettings.theme}-100 flex items-center justify-center mr-3">
|
| 705 |
-
<i class="fas fa-briefcase text-${userSettings.theme}-600"></i>
|
| 706 |
-
</div>
|
| 707 |
-
<div>
|
| 708 |
-
<p class="font-medium ${isToday ? `text-${userSettings.theme}-800` : 'text-gray-800'}">${formattedEntryDate}</p>
|
| 709 |
-
${entry.notes ? `<p class="text-xs text-gray-500 truncate max-w-xs">${entry.notes}</p>` : ''}
|
| 710 |
-
</div>
|
| 711 |
-
</div>
|
| 712 |
-
<div class="flex items-center space-x-2">
|
| 713 |
-
<span class="text-lg font-bold ${isToday ? `text-${userSettings.theme}-800` : 'text-gray-700'}">${entry.count}</span>
|
| 714 |
-
</div>
|
| 715 |
-
`;
|
| 716 |
-
|
| 717 |
-
// Add click handler to edit entry
|
| 718 |
-
historyItem.addEventListener('click', function() {
|
| 719 |
-
customDate.value = entry.date;
|
| 720 |
-
customCount.value = entry.count;
|
| 721 |
-
customNotes.value = entry.notes || '';
|
| 722 |
-
deleteEntryBtn.classList.remove('hidden');
|
| 723 |
-
|
| 724 |
-
// Change save button behavior to update existing entry
|
| 725 |
-
saveCustom.onclick = function() {
|
| 726 |
-
const newCount = parseInt(customCount.value);
|
| 727 |
-
const notes = customNotes.value.trim();
|
| 728 |
-
|
| 729 |
-
if (isNaN(newCount) || newCount < 0) {
|
| 730 |
-
alert('Please enter a valid number of applications');
|
| 731 |
-
return;
|
| 732 |
-
}
|
| 733 |
-
|
| 734 |
-
// Calculate the difference to update total correctly
|
| 735 |
-
const diff = newCount - entry.count;
|
| 736 |
-
entry.count = newCount;
|
| 737 |
-
entry.notes = notes;
|
| 738 |
-
appData.total += diff;
|
| 739 |
-
|
| 740 |
-
// If this is today's entry, update todayEntry reference
|
| 741 |
-
if (entry.date === todayKey) {
|
| 742 |
-
todayEntry = entry;
|
| 743 |
-
}
|
| 744 |
-
|
| 745 |
-
saveData();
|
| 746 |
-
updateCounts();
|
| 747 |
-
renderHistory();
|
| 748 |
-
renderCharts();
|
| 749 |
-
closeModalHandler();
|
| 750 |
-
};
|
| 751 |
-
|
| 752 |
-
openModal();
|
| 753 |
-
});
|
| 754 |
-
|
| 755 |
-
historyList.appendChild(historyItem);
|
| 756 |
-
});
|
| 757 |
}
|
| 758 |
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
-
|
| 764 |
-
|
| 765 |
-
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
// Find max count for scaling
|
| 775 |
-
let maxCount = 1;
|
| 776 |
-
days.forEach(day => {
|
| 777 |
-
const entry = appData.history.find(e => e.date === day);
|
| 778 |
-
if (entry && entry.count > maxCount) {
|
| 779 |
-
maxCount = entry.count;
|
| 780 |
-
}
|
| 781 |
-
});
|
| 782 |
-
|
| 783 |
-
// Create bars for each day
|
| 784 |
-
days.forEach(day => {
|
| 785 |
-
const entry = appData.history.find(e => e.date === day) || { count: 0 };
|
| 786 |
-
const heightPercent = (entry.count / maxCount) * 100;
|
| 787 |
-
const isToday = day === todayKey;
|
| 788 |
-
|
| 789 |
-
const dayName = moment(day).format('ddd');
|
| 790 |
-
|
| 791 |
-
const barContainer = document.createElement('div');
|
| 792 |
-
barContainer.className = 'flex flex-col items-center';
|
| 793 |
-
|
| 794 |
-
const bar = document.createElement('div');
|
| 795 |
-
bar.className = `chart-bar w-8 rounded-t-md bg-${userSettings.theme}-${isToday ? '600' : '400'} mb-1`;
|
| 796 |
-
bar.style.height = `${heightPercent}%`;
|
| 797 |
-
bar.style.minHeight = '4px';
|
| 798 |
-
|
| 799 |
-
const dayLabel = document.createElement('span');
|
| 800 |
-
dayLabel.className = 'text-xs text-gray-500';
|
| 801 |
-
dayLabel.textContent = dayName;
|
| 802 |
-
|
| 803 |
-
const countLabel = document.createElement('span');
|
| 804 |
-
countLabel.className = `text-xs font-medium text-${userSettings.theme}-800`;
|
| 805 |
-
countLabel.textContent = entry.count;
|
| 806 |
-
|
| 807 |
-
barContainer.appendChild(countLabel);
|
| 808 |
-
barContainer.appendChild(bar);
|
| 809 |
-
barContainer.appendChild(dayLabel);
|
| 810 |
-
weeklyChart.appendChild(barContainer);
|
| 811 |
-
});
|
| 812 |
-
|
| 813 |
-
// Monthly chart (simplified)
|
| 814 |
-
const monthlyChart = document.getElementById('monthly-chart');
|
| 815 |
-
monthlyChart.innerHTML = '';
|
| 816 |
-
|
| 817 |
-
// Create a simple bar for monthly progress
|
| 818 |
-
const thisMonth = moment().format('YYYY-MM');
|
| 819 |
-
const monthEntries = appData.history.filter(entry => entry.date.startsWith(thisMonth));
|
| 820 |
-
const monthTotal = monthEntries.reduce((sum, entry) => sum + entry.count, 0);
|
| 821 |
-
|
| 822 |
-
const monthContainer = document.createElement('div');
|
| 823 |
-
monthContainer.className = 'flex flex-col h-full justify-center';
|
| 824 |
-
|
| 825 |
-
const monthBar = document.createElement('div');
|
| 826 |
-
monthBar.className = `h-6 rounded-full bg-${userSettings.theme}-200 relative overflow-hidden`;
|
| 827 |
-
|
| 828 |
-
const monthProgress = document.createElement('div');
|
| 829 |
-
monthProgress.className = `absolute top-0 left-0 h-full bg-${userSettings.theme}-600 rounded-full`;
|
| 830 |
-
monthProgress.style.width = `${Math.min((monthTotal / 50) * 100, 100)}%`;
|
| 831 |
-
|
| 832 |
-
const monthText = document.createElement('div');
|
| 833 |
-
monthText.className = 'flex justify-between items-center mt-2';
|
| 834 |
-
monthText.innerHTML = `
|
| 835 |
-
<span class="text-sm text-gray-600">${moment().format('MMMM')}</span>
|
| 836 |
-
<span class="text-sm font-medium text-${userSettings.theme}-800">${monthTotal} apps</span>
|
| 837 |
-
`;
|
| 838 |
-
|
| 839 |
-
monthBar.appendChild(monthProgress);
|
| 840 |
-
monthContainer.appendChild(monthBar);
|
| 841 |
-
monthContainer.appendChild(monthText);
|
| 842 |
-
monthlyChart.appendChild(monthContainer);
|
| 843 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 844 |
|
| 845 |
-
//
|
| 846 |
-
|
| 847 |
-
|
| 848 |
}
|
|
|
|
|
|
|
| 849 |
});
|
|
|
|
|
|
|
|
|
|
| 850 |
</script>
|
| 851 |
<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=kasramojallal/application-tracker" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 852 |
</html>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Job Application Tracker</title>
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
|
|
|
|
|
| 9 |
<style>
|
| 10 |
+
.progress-bar {
|
| 11 |
+
transition: width 0.5s ease-in-out;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
}
|
| 13 |
.chart-bar {
|
| 14 |
+
transition: height 0.5s ease-in-out;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
}
|
| 16 |
</style>
|
| 17 |
</head>
|
| 18 |
+
<body class="bg-gray-100 min-h-screen">
|
| 19 |
<div class="container mx-auto px-4 py-8 max-w-4xl">
|
| 20 |
+
<!-- Header -->
|
| 21 |
+
<header class="mb-8">
|
| 22 |
+
<h1 class="text-3xl font-bold text-indigo-700 mb-2">Job Application Tracker</h1>
|
| 23 |
+
<p class="text-gray-600">Track your daily job applications and reach your goals</p>
|
| 24 |
</header>
|
| 25 |
|
| 26 |
+
<!-- User Section -->
|
| 27 |
+
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
| 28 |
+
<h2 class="text-xl font-semibold mb-4 text-gray-800">User Profile</h2>
|
| 29 |
+
<div class="flex flex-col md:flex-row gap-4">
|
| 30 |
+
<div class="flex-1">
|
| 31 |
+
<label for="username" class="block text-sm font-medium text-gray-700 mb-1">Username</label>
|
| 32 |
+
<div class="flex">
|
| 33 |
+
<input type="text" id="username" placeholder="Enter your username"
|
| 34 |
+
class="flex-1 px-4 py-2 border border-gray-300 rounded-l-md focus:ring-indigo-500 focus:border-indigo-500">
|
| 35 |
+
<button id="saveUserBtn" class="bg-indigo-600 text-white px-4 py-2 rounded-r-md hover:bg-indigo-700 transition">
|
| 36 |
+
Save
|
| 37 |
+
</button>
|
| 38 |
</div>
|
| 39 |
</div>
|
| 40 |
+
<div class="flex-1">
|
| 41 |
+
<label for="dailyGoal" class="block text-sm font-medium text-gray-700 mb-1">Daily Goal</label>
|
| 42 |
+
<div class="flex">
|
| 43 |
+
<input type="number" id="dailyGoal" min="1" value="30"
|
| 44 |
+
class="flex-1 px-4 py-2 border border-gray-300 rounded-l-md focus:ring-indigo-500 focus:border-indigo-500">
|
| 45 |
+
<button id="saveGoalBtn" class="bg-indigo-600 text-white px-4 py-2 rounded-r-md hover:bg-indigo-700 transition">
|
| 46 |
+
Set Goal
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
</button>
|
| 48 |
</div>
|
| 49 |
</div>
|
| 50 |
</div>
|
| 51 |
+
<div id="currentUser" class="mt-4 text-sm text-gray-600 hidden">
|
| 52 |
+
<span class="font-medium">Current user:</span> <span id="userDisplay"></span> |
|
| 53 |
+
<span class="font-medium">Daily goal:</span> <span id="goalDisplay"></span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
</div>
|
| 55 |
</div>
|
| 56 |
|
| 57 |
+
<!-- Today's Progress -->
|
| 58 |
+
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
| 59 |
+
<h2 class="text-xl font-semibold mb-4 text-gray-800">Today's Progress</h2>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
<div class="mb-4">
|
| 61 |
+
<div class="flex justify-between mb-1">
|
| 62 |
+
<span class="text-sm font-medium text-gray-700">Applications today</span>
|
| 63 |
+
<span id="progressText" class="text-sm font-medium text-gray-700">0/30</span>
|
| 64 |
+
</div>
|
| 65 |
+
<div class="w-full bg-gray-200 rounded-full h-2.5">
|
| 66 |
+
<div id="progressBar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
|
|
|
|
|
|
|
|
|
|
| 67 |
</div>
|
| 68 |
</div>
|
| 69 |
+
<div class="flex items-center justify-center gap-4 mb-4">
|
| 70 |
+
<button id="decreaseBtn" class="bg-red-500 text-white p-3 rounded-full hover:bg-red-600 transition disabled:opacity-50" disabled>
|
| 71 |
+
<i class="fas fa-minus"></i>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
</button>
|
| 73 |
+
<div class="text-4xl font-bold w-20 text-center" id="countDisplay">0</div>
|
| 74 |
+
<button id="increaseBtn" class="bg-green-500 text-white p-3 rounded-full hover:bg-green-600 transition">
|
| 75 |
+
<i class="fas fa-plus"></i>
|
| 76 |
</button>
|
| 77 |
</div>
|
| 78 |
+
<button id="saveTodayBtn" class="w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 transition">
|
| 79 |
+
Save Today's Applications
|
| 80 |
+
</button>
|
| 81 |
</div>
|
|
|
|
| 82 |
|
| 83 |
+
<!-- Weekly History -->
|
| 84 |
+
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
| 85 |
+
<h2 class="text-xl font-semibold mb-4 text-gray-800">Weekly History</h2>
|
| 86 |
+
<div class="flex justify-between items-end h-40 mb-4 border-b border-gray-200">
|
| 87 |
+
<!-- Chart bars will be inserted here by JavaScript -->
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
</div>
|
| 89 |
+
<div class="overflow-x-auto">
|
| 90 |
+
<table class="min-w-full divide-y divide-gray-200">
|
| 91 |
+
<thead class="bg-gray-50">
|
| 92 |
+
<tr>
|
| 93 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
|
| 94 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Applications</th>
|
| 95 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Goal</th>
|
| 96 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
| 97 |
+
</tr>
|
| 98 |
+
</thead>
|
| 99 |
+
<tbody id="historyTable" class="bg-white divide-y divide-gray-200">
|
| 100 |
+
<!-- History rows will be inserted here by JavaScript -->
|
| 101 |
+
</tbody>
|
| 102 |
+
</table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
</div>
|
| 104 |
+
</div>
|
| 105 |
+
|
| 106 |
+
<!-- All Users Data (Admin View) -->
|
| 107 |
+
<div id="adminSection" class="bg-white rounded-lg shadow-md p-6 hidden">
|
| 108 |
+
<h2 class="text-xl font-semibold mb-4 text-gray-800">All Users Data</h2>
|
| 109 |
+
<div class="overflow-x-auto">
|
| 110 |
+
<table class="min-w-full divide-y divide-gray-200">
|
| 111 |
+
<thead class="bg-gray-50">
|
| 112 |
+
<tr>
|
| 113 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User</th>
|
| 114 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Today</th>
|
| 115 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Weekly Avg</th>
|
| 116 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total</th>
|
| 117 |
+
</tr>
|
| 118 |
+
</thead>
|
| 119 |
+
<tbody id="usersTable" class="bg-white divide-y divide-gray-200">
|
| 120 |
+
<!-- Users data will be inserted here by JavaScript -->
|
| 121 |
+
</tbody>
|
| 122 |
+
</table>
|
| 123 |
</div>
|
| 124 |
</div>
|
| 125 |
</div>
|
| 126 |
|
| 127 |
<script>
|
| 128 |
+
// DOM Elements
|
| 129 |
+
const usernameInput = document.getElementById('username');
|
| 130 |
+
const saveUserBtn = document.getElementById('saveUserBtn');
|
| 131 |
+
const dailyGoalInput = document.getElementById('dailyGoal');
|
| 132 |
+
const saveGoalBtn = document.getElementById('saveGoalBtn');
|
| 133 |
+
const currentUserDiv = document.getElementById('currentUser');
|
| 134 |
+
const userDisplay = document.getElementById('userDisplay');
|
| 135 |
+
const goalDisplay = document.getElementById('goalDisplay');
|
| 136 |
+
const decreaseBtn = document.getElementById('decreaseBtn');
|
| 137 |
+
const increaseBtn = document.getElementById('increaseBtn');
|
| 138 |
+
const countDisplay = document.getElementById('countDisplay');
|
| 139 |
+
const progressText = document.getElementById('progressText');
|
| 140 |
+
const progressBar = document.getElementById('progressBar');
|
| 141 |
+
const saveTodayBtn = document.getElementById('saveTodayBtn');
|
| 142 |
+
const historyTable = document.getElementById('historyTable');
|
| 143 |
+
const adminSection = document.getElementById('adminSection');
|
| 144 |
+
const usersTable = document.getElementById('usersTable');
|
| 145 |
+
|
| 146 |
+
// State
|
| 147 |
+
let currentUser = localStorage.getItem('currentUser') || '';
|
| 148 |
+
let dailyGoal = parseInt(localStorage.getItem(`${currentUser}_dailyGoal`)) || 30;
|
| 149 |
+
let todayCount = 0;
|
| 150 |
+
let applicationsData = JSON.parse(localStorage.getItem('applicationsData')) || {};
|
| 151 |
+
let allUsersData = JSON.parse(localStorage.getItem('allUsersData')) || {};
|
| 152 |
+
|
| 153 |
+
// Initialize
|
| 154 |
+
function init() {
|
| 155 |
+
if (currentUser) {
|
| 156 |
+
usernameInput.value = currentUser;
|
| 157 |
+
dailyGoalInput.value = dailyGoal;
|
| 158 |
+
showCurrentUser();
|
| 159 |
+
loadTodayCount();
|
| 160 |
+
loadHistory();
|
| 161 |
+
loadAllUsersData();
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
// Check if current user is admin
|
| 165 |
+
if (currentUser === 'admin') {
|
| 166 |
+
adminSection.classList.remove('hidden');
|
| 167 |
+
}
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
// Show current user info
|
| 171 |
+
function showCurrentUser() {
|
| 172 |
+
currentUserDiv.classList.remove('hidden');
|
| 173 |
+
userDisplay.textContent = currentUser;
|
| 174 |
+
goalDisplay.textContent = dailyGoal;
|
| 175 |
+
progressText.textContent = `0/${dailyGoal}`;
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
// Load today's count
|
| 179 |
+
function loadTodayCount() {
|
| 180 |
+
const today = new Date().toISOString().split('T')[0];
|
| 181 |
+
if (applicationsData[currentUser] && applicationsData[currentUser][today]) {
|
| 182 |
+
todayCount = applicationsData[currentUser][today].count;
|
| 183 |
+
updateCountDisplay();
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
// Update count display
|
| 188 |
+
function updateCountDisplay() {
|
| 189 |
+
countDisplay.textContent = todayCount;
|
| 190 |
+
progressText.textContent = `${todayCount}/${dailyGoal}`;
|
| 191 |
+
const progressPercentage = Math.min((todayCount / dailyGoal) * 100, 100);
|
| 192 |
+
progressBar.style.width = `${progressPercentage}%`;
|
| 193 |
+
|
| 194 |
+
// Change progress bar color based on completion
|
| 195 |
+
if (progressPercentage >= 100) {
|
| 196 |
+
progressBar.classList.remove('bg-indigo-600');
|
| 197 |
+
progressBar.classList.add('bg-green-500');
|
| 198 |
+
} else if (progressPercentage >= 75) {
|
| 199 |
+
progressBar.classList.remove('bg-green-500', 'bg-yellow-500');
|
| 200 |
+
progressBar.classList.add('bg-indigo-600');
|
| 201 |
+
} else if (progressPercentage >= 50) {
|
| 202 |
+
progressBar.classList.remove('bg-indigo-600', 'bg-red-500');
|
| 203 |
+
progressBar.classList.add('bg-yellow-500');
|
| 204 |
+
} else {
|
| 205 |
+
progressBar.classList.remove('bg-indigo-600', 'bg-yellow-500');
|
| 206 |
+
progressBar.classList.add('bg-red-500');
|
| 207 |
+
}
|
| 208 |
|
| 209 |
+
// Enable/disable buttons
|
| 210 |
+
decreaseBtn.disabled = todayCount <= 0;
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
// Load history
|
| 214 |
+
function loadHistory() {
|
| 215 |
+
if (!applicationsData[currentUser]) {
|
| 216 |
+
historyTable.innerHTML = '<tr><td colspan="4" class="px-6 py-4 text-center text-gray-500">No data available</td></tr>';
|
| 217 |
+
return;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
// Clear existing rows
|
| 221 |
+
historyTable.innerHTML = '';
|
| 222 |
|
| 223 |
+
// Get sorted dates (newest first)
|
| 224 |
+
const userData = applicationsData[currentUser];
|
| 225 |
+
const dates = Object.keys(userData).sort((a, b) => new Date(b) - new Date(a));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
|
| 227 |
+
// Limit to 30 entries for display
|
| 228 |
+
const displayDates = dates.slice(0, 30);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
|
| 230 |
+
// Create chart
|
| 231 |
+
createWeeklyChart(displayDates.slice(0, 7).reverse());
|
| 232 |
+
|
| 233 |
+
// Add rows
|
| 234 |
+
displayDates.forEach(date => {
|
| 235 |
+
const entry = userData[date];
|
| 236 |
+
const row = document.createElement('tr');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
+
const dateCell = document.createElement('td');
|
| 239 |
+
dateCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
|
| 240 |
+
dateCell.textContent = formatDate(date);
|
|
|
|
| 241 |
|
| 242 |
+
const countCell = document.createElement('td');
|
| 243 |
+
countCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
|
| 244 |
+
countCell.textContent = entry.count;
|
| 245 |
|
| 246 |
+
const goalCell = document.createElement('td');
|
| 247 |
+
goalCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
|
| 248 |
+
goalCell.textContent = entry.goal;
|
| 249 |
|
| 250 |
+
const statusCell = document.createElement('td');
|
| 251 |
+
statusCell.className = 'px-6 py-4 whitespace-nowrap text-sm';
|
|
|
|
| 252 |
|
| 253 |
+
const statusSpan = document.createElement('span');
|
| 254 |
+
statusSpan.className = entry.count >= entry.goal ?
|
| 255 |
+
'px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800' :
|
| 256 |
+
'px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800';
|
| 257 |
+
statusSpan.textContent = entry.count >= entry.goal ? 'Completed' : 'Pending';
|
| 258 |
|
| 259 |
+
statusCell.appendChild(statusSpan);
|
|
|
|
|
|
|
|
|
|
| 260 |
|
| 261 |
+
row.appendChild(dateCell);
|
| 262 |
+
row.appendChild(countCell);
|
| 263 |
+
row.appendChild(goalCell);
|
| 264 |
+
row.appendChild(statusCell);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 265 |
|
| 266 |
+
historyTable.appendChild(row);
|
| 267 |
+
});
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
// Create weekly chart
|
| 271 |
+
function createWeeklyChart(dates) {
|
| 272 |
+
const chartContainer = document.querySelector('.flex.justify-between.items-end');
|
| 273 |
+
chartContainer.innerHTML = '';
|
| 274 |
+
|
| 275 |
+
if (!dates.length) return;
|
| 276 |
+
|
| 277 |
+
// Find max value for scaling
|
| 278 |
+
const maxValue = Math.max(...dates.map(date => {
|
| 279 |
+
return applicationsData[currentUser][date].count;
|
| 280 |
+
}), dailyGoal);
|
| 281 |
+
|
| 282 |
+
dates.forEach(date => {
|
| 283 |
+
const entry = applicationsData[currentUser][date];
|
| 284 |
+
const day = new Date(date).toLocaleDateString('en-US', { weekday: 'short' });
|
| 285 |
+
const count = entry.count;
|
| 286 |
+
const goal = entry.goal;
|
| 287 |
+
|
| 288 |
+
const barContainer = document.createElement('div');
|
| 289 |
+
barContainer.className = 'flex flex-col items-center';
|
| 290 |
+
|
| 291 |
+
const barWrapper = document.createElement('div');
|
| 292 |
+
barWrapper.className = 'relative h-32 w-10';
|
| 293 |
+
|
| 294 |
+
// Goal bar (background)
|
| 295 |
+
const goalBar = document.createElement('div');
|
| 296 |
+
goalBar.className = 'absolute bottom-0 w-full bg-gray-200 rounded-t';
|
| 297 |
+
goalBar.style.height = `${(goal / maxValue) * 100}%`;
|
| 298 |
+
|
| 299 |
+
// Count bar (foreground)
|
| 300 |
+
const countBar = document.createElement('div');
|
| 301 |
+
countBar.className = 'chart-bar absolute bottom-0 w-full bg-indigo-600 rounded-t';
|
| 302 |
+
countBar.style.height = `${(count / maxValue) * 100}%`;
|
| 303 |
+
|
| 304 |
+
// Label
|
| 305 |
+
const label = document.createElement('div');
|
| 306 |
+
label.className = 'text-xs text-gray-500 mt-1';
|
| 307 |
+
label.textContent = day;
|
| 308 |
+
|
| 309 |
+
barWrapper.appendChild(goalBar);
|
| 310 |
+
barWrapper.appendChild(countBar);
|
| 311 |
+
barContainer.appendChild(barWrapper);
|
| 312 |
+
barContainer.appendChild(label);
|
| 313 |
+
|
| 314 |
+
chartContainer.appendChild(barContainer);
|
| 315 |
+
});
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
// Load all users data (for admin)
|
| 319 |
+
function loadAllUsersData() {
|
| 320 |
+
if (currentUser !== 'admin') return;
|
|
|
|
| 321 |
|
| 322 |
+
usersTable.innerHTML = '';
|
|
|
|
| 323 |
|
| 324 |
+
const users = Object.keys(allUsersData);
|
| 325 |
+
if (users.length === 0) {
|
| 326 |
+
usersTable.innerHTML = '<tr><td colspan="4" class="px-6 py-4 text-center text-gray-500">No user data available</td></tr>';
|
| 327 |
+
return;
|
| 328 |
}
|
| 329 |
|
| 330 |
+
users.forEach(user => {
|
| 331 |
+
if (user === 'admin') return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
|
| 333 |
+
const userData = allUsersData[user];
|
| 334 |
+
const today = new Date().toISOString().split('T')[0];
|
| 335 |
+
const todayCount = userData.applications[today] ? userData.applications[today].count : 0;
|
| 336 |
|
| 337 |
+
// Calculate weekly average
|
| 338 |
+
const dates = Object.keys(userData.applications);
|
| 339 |
+
const last7Days = dates
|
| 340 |
+
.filter(date => {
|
| 341 |
+
const dateObj = new Date(date);
|
| 342 |
+
const todayObj = new Date();
|
| 343 |
+
return dateObj >= new Date(todayObj.setDate(todayObj.getDate() - 7));
|
| 344 |
+
})
|
| 345 |
+
.map(date => userData.applications[date].count);
|
|
|
|
|
|
|
| 346 |
|
| 347 |
+
const weeklyAvg = last7Days.length > 0 ?
|
| 348 |
+
Math.round(last7Days.reduce((a, b) => a + b, 0) / last7Days.length) : 0;
|
|
|
|
| 349 |
|
| 350 |
+
// Calculate total
|
| 351 |
+
const total = dates.reduce((sum, date) => sum + userData.applications[date].count, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
|
| 353 |
+
const row = document.createElement('tr');
|
| 354 |
+
|
| 355 |
+
const userCell = document.createElement('td');
|
| 356 |
+
userCell.className = 'px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900';
|
| 357 |
+
userCell.textContent = user;
|
| 358 |
+
|
| 359 |
+
const todayCell = document.createElement('td');
|
| 360 |
+
todayCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
|
| 361 |
+
todayCell.textContent = todayCount;
|
| 362 |
+
|
| 363 |
+
const weeklyCell = document.createElement('td');
|
| 364 |
+
weeklyCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
|
| 365 |
+
weeklyCell.textContent = weeklyAvg;
|
| 366 |
+
|
| 367 |
+
const totalCell = document.createElement('td');
|
| 368 |
+
totalCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
|
| 369 |
+
totalCell.textContent = total;
|
| 370 |
+
|
| 371 |
+
row.appendChild(userCell);
|
| 372 |
+
row.appendChild(todayCell);
|
| 373 |
+
row.appendChild(weeklyCell);
|
| 374 |
+
row.appendChild(totalCell);
|
| 375 |
+
|
| 376 |
+
usersTable.appendChild(row);
|
| 377 |
});
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
// Format date for display
|
| 381 |
+
function formatDate(dateString) {
|
| 382 |
+
const options = { year: 'numeric', month: 'short', day: 'numeric', weekday: 'short' };
|
| 383 |
+
return new Date(dateString).toLocaleDateString('en-US', options);
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
// Event Listeners
|
| 387 |
+
saveUserBtn.addEventListener('click', () => {
|
| 388 |
+
const newUser = usernameInput.value.trim();
|
| 389 |
+
if (!newUser) {
|
| 390 |
+
alert('Please enter a username');
|
| 391 |
+
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
}
|
| 393 |
|
| 394 |
+
currentUser = newUser;
|
| 395 |
+
localStorage.setItem('currentUser', currentUser);
|
| 396 |
|
| 397 |
+
// Initialize user data if it doesn't exist
|
| 398 |
+
if (!applicationsData[currentUser]) {
|
| 399 |
+
applicationsData[currentUser] = {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 400 |
}
|
| 401 |
|
| 402 |
+
// Initialize allUsersData if it doesn't exist
|
| 403 |
+
if (!allUsersData[currentUser]) {
|
| 404 |
+
allUsersData[currentUser] = {
|
| 405 |
+
goal: dailyGoal,
|
| 406 |
+
applications: {}
|
| 407 |
+
};
|
| 408 |
+
localStorage.setItem('allUsersData', JSON.stringify(allUsersData));
|
| 409 |
}
|
| 410 |
|
| 411 |
+
// Load user's daily goal
|
| 412 |
+
dailyGoal = allUsersData[currentUser].goal || 30;
|
| 413 |
+
dailyGoalInput.value = dailyGoal;
|
| 414 |
|
| 415 |
+
showCurrentUser();
|
| 416 |
+
loadTodayCount();
|
| 417 |
+
loadHistory();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 418 |
|
| 419 |
+
// Show admin section if user is admin
|
| 420 |
+
if (currentUser === 'admin') {
|
| 421 |
+
adminSection.classList.remove('hidden');
|
| 422 |
+
loadAllUsersData();
|
| 423 |
+
} else {
|
| 424 |
+
adminSection.classList.add('hidden');
|
| 425 |
+
}
|
| 426 |
+
});
|
| 427 |
+
|
| 428 |
+
saveGoalBtn.addEventListener('click', () => {
|
| 429 |
+
const newGoal = parseInt(dailyGoalInput.value);
|
| 430 |
+
if (isNaN(newGoal) || newGoal < 1) {
|
| 431 |
+
alert('Please enter a valid goal (minimum 1)');
|
| 432 |
+
return;
|
| 433 |
+
}
|
| 434 |
|
| 435 |
+
dailyGoal = newGoal;
|
| 436 |
+
goalDisplay.textContent = dailyGoal;
|
| 437 |
+
progressText.textContent = `${todayCount}/${dailyGoal}`;
|
| 438 |
+
|
| 439 |
+
// Save goal for current user
|
| 440 |
+
if (currentUser) {
|
| 441 |
+
if (!allUsersData[currentUser]) {
|
| 442 |
+
allUsersData[currentUser] = {
|
| 443 |
+
goal: dailyGoal,
|
| 444 |
+
applications: {}
|
| 445 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 446 |
} else {
|
| 447 |
+
allUsersData[currentUser].goal = dailyGoal;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 448 |
}
|
| 449 |
|
| 450 |
+
localStorage.setItem('allUsersData', JSON.stringify(allUsersData));
|
| 451 |
+
localStorage.setItem(`${currentUser}_dailyGoal`, dailyGoal);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 452 |
}
|
| 453 |
|
| 454 |
+
updateCountDisplay();
|
| 455 |
+
});
|
| 456 |
+
|
| 457 |
+
increaseBtn.addEventListener('click', () => {
|
| 458 |
+
todayCount++;
|
| 459 |
+
updateCountDisplay();
|
| 460 |
+
});
|
| 461 |
+
|
| 462 |
+
decreaseBtn.addEventListener('click', () => {
|
| 463 |
+
if (todayCount > 0) {
|
| 464 |
+
todayCount--;
|
| 465 |
+
updateCountDisplay();
|
| 466 |
+
}
|
| 467 |
+
});
|
| 468 |
+
|
| 469 |
+
saveTodayBtn.addEventListener('click', () => {
|
| 470 |
+
if (!currentUser) {
|
| 471 |
+
alert('Please set a username first');
|
| 472 |
+
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
}
|
| 474 |
|
| 475 |
+
const today = new Date().toISOString().split('T')[0];
|
| 476 |
+
|
| 477 |
+
// Save to applicationsData
|
| 478 |
+
applicationsData[currentUser][today] = {
|
| 479 |
+
count: todayCount,
|
| 480 |
+
goal: dailyGoal
|
| 481 |
+
};
|
| 482 |
+
localStorage.setItem('applicationsData', JSON.stringify(applicationsData));
|
| 483 |
+
|
| 484 |
+
// Save to allUsersData
|
| 485 |
+
if (!allUsersData[currentUser]) {
|
| 486 |
+
allUsersData[currentUser] = {
|
| 487 |
+
goal: dailyGoal,
|
| 488 |
+
applications: {}
|
| 489 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 490 |
}
|
| 491 |
+
allUsersData[currentUser].applications[today] = {
|
| 492 |
+
count: todayCount,
|
| 493 |
+
goal: dailyGoal
|
| 494 |
+
};
|
| 495 |
+
localStorage.setItem('allUsersData', JSON.stringify(allUsersData));
|
| 496 |
+
|
| 497 |
+
// Reload history
|
| 498 |
+
loadHistory();
|
| 499 |
|
| 500 |
+
// If admin, reload all users data
|
| 501 |
+
if (currentUser === 'admin') {
|
| 502 |
+
loadAllUsersData();
|
| 503 |
}
|
| 504 |
+
|
| 505 |
+
alert('Today\'s applications saved successfully!');
|
| 506 |
});
|
| 507 |
+
|
| 508 |
+
// Initialize the app
|
| 509 |
+
init();
|
| 510 |
</script>
|
| 511 |
<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=kasramojallal/application-tracker" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 512 |
</html>
|
prompts.txt
CHANGED
|
@@ -1,2 +1,4 @@
|
|
| 1 |
add a few functionalities for me to also decrease the number if I added by mistake. also let me choose another date if I want to add the number for previous days.
|
| 2 |
-
add option for decreasing as well. also you got the todays date wrong. add the option to add time zone or location so it can figure the todays day correct. also make the visualization better and delete the clear data option. add as many editing options as possible.
|
|
|
|
|
|
|
|
|
| 1 |
add a few functionalities for me to also decrease the number if I added by mistake. also let me choose another date if I want to add the number for previous days.
|
| 2 |
+
add option for decreasing as well. also you got the todays date wrong. add the option to add time zone or location so it can figure the todays day correct. also make the visualization better and delete the clear data option. add as many editing options as possible.
|
| 3 |
+
the website is not working. fix the issue and forget about detecting timezone we can add it manually.
|
| 4 |
+
I want you to create a job application tracker for me so that I can add each day I applied for how many jobs and there should be a add and decrease button and also it should show the history of the number of jobs I applied each day and there should be a weekly history and each day I should set a goal of like 30 jobs that it should be filled. also I want other peolpe to use it so I want them to be able to add their username.
|