132 lines
3.9 KiB
JavaScript

/**
* Common utilities for the SciPaperLoader application
*/
/**
* Display a flash message to the user
* @param {string} message - The message to display
* @param {string} type - The type of message (success, error, warning, info)
*/
function showFlashMessage(message, type) {
const flashContainer = document.createElement("div");
flashContainer.className = `alert alert-${
type === "error" ? "danger" : type
} alert-dismissible fade show`;
flashContainer.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
`;
// Use the existing client flash container at the top of the page
const clientFlashContainer = document.getElementById("clientFlashContainer");
if (clientFlashContainer) {
clientFlashContainer.appendChild(flashContainer);
} else {
// Fallback to body if container not found
document.body.appendChild(flashContainer);
}
// Auto dismiss after 5 seconds
setTimeout(() => {
flashContainer.classList.remove("show");
setTimeout(() => {
flashContainer.remove();
}, 150); // Remove after fade out animation
}, 5000);
}
/**
* Create a status badge HTML element
* @param {string} status - The status to create a badge for
* @returns {string} HTML string for the status badge
*/
function createStatusBadge(status) {
switch (status) {
case "New":
return '<span class="badge bg-info">New</span>';
case "Pending":
return '<span class="badge bg-warning text-dark">Pending</span>';
case "Done":
return '<span class="badge bg-success">Done</span>';
case "Failed":
return '<span class="badge bg-danger">Failed</span>';
case "success":
return '<span class="badge bg-success">Success</span>';
case "error":
return '<span class="badge bg-danger">Error</span>';
case "pending":
return '<span class="badge bg-warning text-dark">Pending</span>';
default:
return `<span class="badge bg-secondary">${status}</span>`;
}
}
/**
* Format a timestamp to a readable time string
* @param {string} timestamp - ISO timestamp string
* @returns {string} Formatted time string
*/
function formatTimestamp(timestamp) {
const date = new Date(timestamp);
return date.toLocaleTimeString("de-DE", {
year: "2-digit",
month: "numeric",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
}
/**
* Truncate text to a specified length
* @param {string} text - The text to truncate
* @param {number} maxLength - Maximum length before truncation
* @returns {string} Truncated text with ellipsis if needed
*/
function truncateText(text, maxLength) {
return text.length > maxLength ? text.substring(0, maxLength) + "..." : text;
}
/**
* Toggle button loading state
* @param {HTMLElement} button - The button element
* @param {boolean} loading - Whether to show loading state
* @param {string} loadingText - Text to show when loading
*/
function toggleButtonLoading(button, loading, loadingText = "Loading...") {
if (loading) {
button.disabled = true;
button.dataset.originalText = button.innerHTML;
button.innerHTML = `<i class="fas fa-spinner fa-spin"></i> ${loadingText}`;
} else {
button.disabled = false;
button.innerHTML = button.dataset.originalText || button.innerHTML;
}
}
/**
* Generic fetch wrapper with error handling
* @param {string} url - The URL to fetch
* @param {object} options - Fetch options
* @returns {Promise} Fetch promise
*/
async function apiRequest(url, options = {}) {
const defaultOptions = {
headers: {
"Content-Type": "application/json",
},
};
const mergedOptions = { ...defaultOptions, ...options };
try {
const response = await fetch(url, mergedOptions);
const data = await response.json();
return data;
} catch (error) {
console.error(`API request failed for ${url}:`, error);
throw error;
}
}