Initial Codes
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
/* QBO Excel Sync - Main JavaScript */
|
||||
|
||||
// Toast notification system
|
||||
function showToast(message, type = 'info', duration = 4000) {
|
||||
let container = document.querySelector('.toast-container');
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
container.className = 'toast-container';
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
toast.innerHTML = `
|
||||
<span class="toast-message">${escapeHtml(message)}</span>
|
||||
<button class="toast-close" onclick="this.parentElement.remove()">×</button>
|
||||
`;
|
||||
container.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.style.animation = 'toast-out 0.3s ease forwards';
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
// HTML escape utility
|
||||
function escapeHtml(text) {
|
||||
if (text === null || text === undefined) return '';
|
||||
const div = document.createElement('div');
|
||||
div.textContent = String(text);
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// Format date for display
|
||||
function formatDate(dateString) {
|
||||
if (!dateString) return '';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
}
|
||||
|
||||
// Format currency for display
|
||||
function formatCurrency(amount, currency = 'USD') {
|
||||
if (amount === null || amount === undefined) return '';
|
||||
return new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: currency
|
||||
}).format(amount);
|
||||
}
|
||||
|
||||
// Debounce function for search inputs
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(timeout);
|
||||
func(...args);
|
||||
};
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// API request helper with error handling
|
||||
async function apiRequest(url, options = {}) {
|
||||
const defaultOptions = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, { ...defaultOptions, ...options });
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || `HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('API request error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirm dialog helper
|
||||
function confirmAction(message) {
|
||||
return confirm(message);
|
||||
}
|
||||
|
||||
// Loading state management
|
||||
function setLoading(element, isLoading, loadingText = 'Loading...') {
|
||||
if (isLoading) {
|
||||
element.dataset.originalText = element.textContent;
|
||||
element.textContent = loadingText;
|
||||
element.disabled = true;
|
||||
} else {
|
||||
element.textContent = element.dataset.originalText || element.textContent;
|
||||
element.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize tooltips (basic implementation)
|
||||
function initTooltips() {
|
||||
document.querySelectorAll('[data-tooltip]').forEach(el => {
|
||||
el.addEventListener('mouseenter', () => {
|
||||
const tooltip = document.createElement('div');
|
||||
tooltip.className = 'tooltip';
|
||||
tooltip.textContent = el.dataset.tooltip;
|
||||
document.body.appendChild(tooltip);
|
||||
|
||||
const rect = el.getBoundingClientRect();
|
||||
tooltip.style.top = `${rect.top - tooltip.offsetHeight - 8}px`;
|
||||
tooltip.style.left = `${rect.left + (rect.width - tooltip.offsetWidth) / 2}px`;
|
||||
|
||||
el._tooltip = tooltip;
|
||||
});
|
||||
|
||||
el.addEventListener('mouseleave', () => {
|
||||
if (el._tooltip) {
|
||||
el._tooltip.remove();
|
||||
delete el._tooltip;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Copy to clipboard
|
||||
async function copyToClipboard(text) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
showToast('Copied to clipboard', 'success');
|
||||
} catch (err) {
|
||||
showToast('Failed to copy', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// File size formatter
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
// Check connection status
|
||||
async function checkConnectionStatus() {
|
||||
try {
|
||||
const response = await fetch('/api/connection/test');
|
||||
const data = await response.json();
|
||||
return data.connected === true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Update connection indicator
|
||||
function updateConnectionIndicator(isConnected) {
|
||||
const indicator = document.querySelector('.connection-status');
|
||||
if (indicator) {
|
||||
indicator.className = `connection-status ${isConnected ? 'connected' : 'disconnected'}`;
|
||||
indicator.querySelector('span:last-child').textContent = isConnected ? 'Connected' : 'Not Connected';
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize on DOM ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initTooltips();
|
||||
|
||||
// Add active class to current nav item
|
||||
const currentPath = window.location.pathname;
|
||||
document.querySelectorAll('.nav-link').forEach(link => {
|
||||
if (link.getAttribute('href') === currentPath) {
|
||||
link.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Export for use in other scripts
|
||||
window.QBO = {
|
||||
showToast,
|
||||
escapeHtml,
|
||||
formatDate,
|
||||
formatCurrency,
|
||||
debounce,
|
||||
apiRequest,
|
||||
confirmAction,
|
||||
setLoading,
|
||||
copyToClipboard,
|
||||
formatFileSize,
|
||||
checkConnectionStatus,
|
||||
updateConnectionIndicator
|
||||
};
|
||||
Reference in New Issue
Block a user