Update dashboard

This commit is contained in:
2025-09-01 13:20:52 -04:00
parent f3dbaf2b81
commit 22dd08754f
4 changed files with 300 additions and 16 deletions
+67
View File
@@ -1270,3 +1270,70 @@
max-width: calc(100vw - 2rem);
}
}
/* Enhanced QR Action Buttons */
.qr-action-btn.copy {
background: linear-gradient(135deg, #10b981, #059669);
color: white;
}
.qr-action-btn.copy:hover {
background: linear-gradient(135deg, #059669, #047857);
transform: translateY(-1px);
}
.qr-action-btn.link {
background: linear-gradient(135deg, #3b82f6, #2563eb);
color: white;
}
.qr-action-btn.link:hover {
background: linear-gradient(135deg, #2563eb, #1d4ed8);
transform: translateY(-1px);
}
/* Check-ins Counter Styling */
.qr-checkins-count {
background: rgba(59, 130, 246, 0.1);
border: 1px solid rgba(59, 130, 246, 0.2);
border-radius: var(--radius-md);
padding: 0.25rem 0.5rem;
font-weight: 500;
color: #1e40af;
}
.qr-checkins-count i {
color: #3b82f6;
}
/* Responsive Action Buttons */
@media (max-width: 768px) {
.qr-actions-compact {
flex-wrap: wrap;
gap: 0.25rem;
}
.qr-action-btn {
min-width: 32px;
height: 32px;
font-size: 0.75rem;
}
}
/* Enhanced QR Actions Layout */
.qr-actions-compact {
display: flex;
gap: 0.5rem;
align-items: center;
flex-wrap: wrap;
}
.qr-card-actions {
display: flex;
gap: 0.5rem;
justify-content: center;
flex-wrap: wrap;
padding: var(--spacing-3);
border-top: 1px solid var(--gray-200);
background: var(--gray-50);
}
+121 -13
View File
@@ -188,10 +188,13 @@ class DashboardManager {
try {
// Show loading state
const deleteBtn = document.querySelector(`[onclick*="deleteQRCode(${qrId}"]`);
const deleteBtn = document.querySelector(
`[onclick*="deleteQRCode(${qrId}"]`
);
if (deleteBtn) {
deleteBtn.disabled = true;
deleteBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Deleting...';
deleteBtn.innerHTML =
'<i class="fas fa-spinner fa-spin"></i> Deleting...';
}
const response = await fetch(`/qr-codes/${qrId}/delete`, {
@@ -216,26 +219,25 @@ class DashboardManager {
// Use simple alert instead of problematic showToast
alert(`QR code "${qrName}" deleted successfully!`);
} else {
throw new Error(`Server error: ${response.status}`);
}
} catch (error) {
console.error("Delete error:", error);
// Restore button if there was an error
const deleteBtn = document.querySelector(`[onclick*="deleteQRCode(${qrId}"]`);
const deleteBtn = document.querySelector(
`[onclick*="deleteQRCode(${qrId}"]`
);
if (deleteBtn) {
deleteBtn.disabled = false;
deleteBtn.innerHTML = '<i class="fas fa-trash"></i>';
}
// Use simple alert instead of problematic showToast
alert("Failed to delete QR code. Please try again.");
}
}
// Show custom delete confirmation dialog
showDeleteConfirmation(qrName) {
@@ -299,19 +301,26 @@ class DashboardManager {
async bulkDeleteQRCodes() {
if (this.selectedQRCodes.size === 0) return;
const confirmed = await this.showBulkDeleteConfirmation(this.selectedQRCodes.size);
const confirmed = await this.showBulkDeleteConfirmation(
this.selectedQRCodes.size
);
if (!confirmed) return;
const deletePromises = Array.from(this.selectedQRCodes).map(qrId => {
const deletePromises = Array.from(this.selectedQRCodes).map((qrId) => {
const qrItem = document.querySelector(`[data-qr-id="${qrId}"]`);
const qrName = qrItem ? qrItem.querySelector('.qr-name')?.textContent || 'Unknown' : 'Unknown';
const qrName = qrItem
? qrItem.querySelector(".qr-name")?.textContent || "Unknown"
: "Unknown";
return this.deleteQRCode(qrId, qrName);
});
try {
await Promise.all(deletePromises);
this.selectedQRCodes.clear();
window.showToast(`Successfully deleted ${deletePromises.length} QR codes`, "success");
window.showToast(
`Successfully deleted ${deletePromises.length} QR codes`,
"success"
);
} catch (error) {
console.error("Bulk delete error:", error);
window.showToast("Some QR codes could not be deleted", "error");
@@ -437,6 +446,96 @@ class DashboardManager {
counter.textContent = `${qrItems.length} results`;
}
}
showToast(message, type = "info") {
// Create toast if showToast doesn't exist globally
if (typeof window.showToast === "function") {
window.showToast(message, type);
} else {
// Fallback to console or simple alert
console.log(`${type.toUpperCase()}: ${message}`);
// Or use a simple notification
const toast = document.createElement("div");
toast.className = `toast toast-${type}`;
toast.textContent = message;
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${
type === "success"
? "#10b981"
: type === "error"
? "#ef4444"
: "#3b82f6"
};
color: white;
padding: 12px 16px;
border-radius: 8px;
z-index: 9999;
font-weight: 500;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
`;
document.body.appendChild(toast);
setTimeout(() => {
toast.style.opacity = "0";
toast.style.transform = "translateX(100%)";
setTimeout(() => toast.remove(), 300);
}, 3000);
}
}
// Copy QR Code URL
async copyQRUrl(qrId) {
try {
const response = await fetch(`/qr-codes/${qrId}/copy-url`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
const data = await response.json();
if (data.success && data.url) {
// Copy to clipboard
await navigator.clipboard.writeText(data.url);
this.showToast("QR code URL copied to clipboard!", "success");
} else {
this.showToast("Failed to copy URL", "error");
}
} catch (error) {
console.error("Copy URL error:", error);
this.showToast("Failed to copy URL", "error");
}
}
// Open QR Code Link
async openQRLink(qrId) {
try {
const response = await fetch(`/qr-codes/${qrId}/open-link`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
const data = await response.json();
if (data.success && data.url) {
// Open in new tab
window.open(data.url, "_blank");
this.showToast("QR code link opened!", "success");
} else {
this.showToast("Failed to open link", "error");
}
} catch (error) {
console.error("Open link error:", error);
this.showToast("Failed to open link", "error");
}
}
}
// Initialize dashboard when DOM is loaded
@@ -454,4 +553,13 @@ document.addEventListener("DOMContentLoaded", function () {
window.dashboardManager.toggleQRItem(element);
window.copyQRData = (name, location, address, event) =>
window.dashboardManager.copyQRData(name, location, address, event);
});
});
// Global functions for new features
function copyQRUrl(qrId) {
window.dashboardManager?.copyQRUrl(qrId);
}
function openQRLink(qrId) {
window.dashboardManager?.openQRLink(qrId);
}