summaryrefslogtreecommitdiff
path: root/web/static/js/app.js
diff options
context:
space:
mode:
Diffstat (limited to 'web/static/js/app.js')
-rw-r--r--web/static/js/app.js190
1 files changed, 146 insertions, 44 deletions
diff --git a/web/static/js/app.js b/web/static/js/app.js
index a96c05d..b68b12a 100644
--- a/web/static/js/app.js
+++ b/web/static/js/app.js
@@ -1,77 +1,179 @@
-// Personal Dashboard JavaScript
+// Personal Dashboard JavaScript with HTMX Integration
-// Auto-refresh every 5 minutes
+// Constants
const AUTO_REFRESH_INTERVAL = 5 * 60 * 1000; // 5 minutes in milliseconds
-// Initialize auto-refresh on page load
+// Track current active tab
+let currentTab = 'tasks';
+let autoRefreshTimer = null;
+
+// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
- // Set up auto-refresh
- setInterval(autoRefresh, AUTO_REFRESH_INTERVAL);
+ console.log('Dashboard initialized');
+
+ // Set up HTMX event listeners
+ setupHtmxListeners();
+
+ // Start auto-refresh
+ startAutoRefresh();
});
-// Auto-refresh function
-async function autoRefresh() {
- console.log('Auto-refreshing data...');
- try {
- const response = await fetch('/api/refresh', {
- method: 'POST'
- });
+// HTMX Event Listeners
+function setupHtmxListeners() {
+ // Before HTMX request
+ document.body.addEventListener('htmx:beforeRequest', function(evt) {
+ const target = evt.detail.target;
+ if (target.id === 'tab-content') {
+ // Show loading state
+ target.classList.add('opacity-50', 'pointer-events-none');
+ }
+ });
- if (response.ok) {
- // Reload the page to show updated data
- window.location.reload();
+ // After HTMX request completes
+ document.body.addEventListener('htmx:afterRequest', function(evt) {
+ const target = evt.detail.target;
+ if (target.id === 'tab-content') {
+ // Hide loading state
+ target.classList.remove('opacity-50', 'pointer-events-none');
+
+ // Update timestamp
+ updateLastUpdatedTime();
}
- } catch (error) {
- console.error('Auto-refresh failed:', error);
- }
+ });
+
+ // Handle HTMX errors
+ document.body.addEventListener('htmx:responseError', function(evt) {
+ console.error('HTMX request failed:', evt.detail);
+ alert('Failed to load content. Please try again.');
+
+ // Remove loading state
+ const target = evt.detail.target;
+ if (target) {
+ target.classList.remove('opacity-50', 'pointer-events-none');
+ }
+ });
+}
+
+// Tab Management
+function setActiveTab(button) {
+ // Remove active class from all tabs
+ document.querySelectorAll('.tab-button').forEach(tab => {
+ tab.classList.remove('tab-button-active');
+ });
+
+ // Add active class to clicked tab
+ button.classList.add('tab-button-active');
+
+ // Extract tab name from hx-get attribute
+ const endpoint = button.getAttribute('hx-get');
+ currentTab = endpoint.split('/').pop(); // "tasks" or "notes"
+
+ console.log('Switched to tab:', currentTab);
+
+ // Reset auto-refresh timer when switching tabs
+ resetAutoRefresh();
}
-// Manual refresh function
+// Manual Refresh
async function refreshData() {
- const button = event.target;
- const originalText = button.textContent;
+ const button = event.target.closest('button');
+ const refreshText = document.getElementById('refresh-text');
+ const originalText = refreshText.textContent;
// Show loading state
button.disabled = true;
- button.innerHTML = 'Refreshing...<span class="spinner"></span>';
+ refreshText.innerHTML = `
+ <svg class="animate-spin h-5 w-5 inline mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
+ </svg>
+ Refreshing...
+ `;
try {
- const response = await fetch('/api/refresh', {
+ // Refresh current tab
+ const response = await fetch(`/tabs/refresh?tab=${currentTab}`, {
method: 'POST'
});
- if (response.ok) {
- // Update last updated time
- const now = new Date();
- const timeString = now.toLocaleTimeString('en-US', {
- hour: 'numeric',
- minute: '2-digit'
- });
- document.getElementById('last-updated').textContent = timeString;
-
- // Reload the page to show updated data
- setTimeout(() => {
- window.location.reload();
- }, 500);
- } else {
- throw new Error('Refresh failed');
- }
+ if (!response.ok) throw new Error('Refresh failed');
+
+ // Get HTML response and update tab content
+ const html = await response.text();
+ document.getElementById('tab-content').innerHTML = html;
+
+ // Update timestamp
+ updateLastUpdatedTime();
+
+ // Reset auto-refresh timer
+ resetAutoRefresh();
+
+ console.log('Manual refresh successful');
+
} catch (error) {
console.error('Refresh failed:', error);
alert('Failed to refresh data. Please try again.');
+ } finally {
+ // Restore button state
button.disabled = false;
- button.textContent = originalText;
+ refreshText.textContent = originalText;
+ }
+}
+
+// Auto-refresh Functions
+function startAutoRefresh() {
+ if (autoRefreshTimer) {
+ clearInterval(autoRefreshTimer);
+ }
+ autoRefreshTimer = setInterval(autoRefresh, AUTO_REFRESH_INTERVAL);
+ console.log('Auto-refresh started (5 min interval)');
+}
+
+function resetAutoRefresh() {
+ clearInterval(autoRefreshTimer);
+ startAutoRefresh();
+}
+
+async function autoRefresh() {
+ console.log(`Auto-refreshing ${currentTab} tab...`);
+
+ try {
+ const response = await fetch(`/tabs/refresh?tab=${currentTab}`, {
+ method: 'POST'
+ });
+
+ if (response.ok) {
+ const html = await response.text();
+ document.getElementById('tab-content').innerHTML = html;
+ updateLastUpdatedTime();
+ console.log('Auto-refresh successful');
+ }
+ } catch (error) {
+ console.error('Auto-refresh failed:', error);
+ }
+}
+
+// Update Last Updated Time
+function updateLastUpdatedTime() {
+ const now = new Date();
+ const timeString = now.toLocaleTimeString('en-US', {
+ hour: 'numeric',
+ minute: '2-digit'
+ });
+ const element = document.getElementById('last-updated');
+ if (element) {
+ element.textContent = timeString;
}
}
-// Filter tasks by status
+// Filter tasks by status (Phase 2 feature)
function filterTasks(status) {
- // This will be implemented in Phase 2
console.log('Filter tasks:', status);
+ // To be implemented in Phase 2
}
-// Toggle task completion
+// Toggle task completion (Phase 2 feature)
function toggleTask(taskId) {
- // This will be implemented in Phase 2
console.log('Toggle task:', taskId);
+ // To be implemented in Phase 2
}