khy_admin/admin-dashboard/src/js/imageManager.js

338 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Image Management Class
class ImageManager {
constructor(dashboard) {
this.dashboard = dashboard;
this.images = [];
this.setupEventListeners();
}
setupEventListeners() {
// Upload images button
document
.getElementById("upload-images-btn")
.addEventListener("click", () => {
this.showUploadModal();
});
}
async loadData() {
try {
// In a real implementation, this would fetch from a server
// For now, we'll collect images from products
this.collectImagesFromProducts();
} catch (error) {
console.error("Error loading image data:", error);
throw error;
}
}
collectImagesFromProducts() {
this.images = [];
const products = this.dashboard.productManager.products;
products.forEach((product) => {
if (product.images && Array.isArray(product.images)) {
product.images.forEach((imagePath) => {
if (!this.images.find((img) => img.path === imagePath)) {
this.images.push({
path: imagePath,
name: this.extractFileName(imagePath),
productId: product.id,
productName: product.name,
size: "Unknown", // Would be fetched from server
uploadDate: "Unknown", // Would be fetched from server
});
}
});
}
});
}
extractFileName(path) {
return path.split("/").pop();
}
renderImages() {
const container = document.getElementById("image-manager");
if (this.images.length === 0) {
container.innerHTML = `
<div class="no-images">
<h3>No images found</h3>
<p>Upload images to get started!</p>
<button class="btn btn-primary" onclick="imageManager.showUploadModal()">Upload Images</button>
</div>
`;
return;
}
container.innerHTML = "";
this.images.forEach((image) => {
const imageItem = this.createImageItem(image);
container.appendChild(imageItem);
});
}
createImageItem(image) {
const item = document.createElement("div");
item.className = "image-item";
item.innerHTML = `
<div class="image-preview">
<img src="${image.path}" alt="${image.name}" onerror="this.src='data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"200\" height=\"150\" viewBox=\"0 0 200 150\"><rect width=\"200\" height=\"150\" fill=\"%23f0f0f0\"/><text x=\"50%\" y=\"50%\" text-anchor=\"middle\" dy=\".3em\" fill=\"%23999\">Image Not Found</text></svg>'">
</div>
<div class="image-item-info">
<div class="image-item-name" title="${image.name}">${image.name}</div>
<div class="image-meta">
<span class="image-product">Product: ${image.productName}</span>
<span class="image-size">Size: ${image.size}</span>
</div>
</div>
<div class="image-item-actions">
<button class="btn btn-sm btn-primary" onclick="imageManager.viewImage('${image.path}')">
👁️ View
</button>
<button class="btn btn-sm btn-secondary" onclick="imageManager.renameImage('${image.path}')">
✏️ Rename
</button>
<button class="btn btn-sm btn-danger" onclick="imageManager.deleteImage('${image.path}')">
🗑️ Delete
</button>
</div>
`;
return item;
}
showUploadModal() {
// Create upload modal if it doesn't exist
let uploadModal = document.getElementById("upload-modal");
if (!uploadModal) {
uploadModal = this.createUploadModal();
document.body.appendChild(uploadModal);
}
uploadModal.style.display = "block";
}
createUploadModal() {
const modal = document.createElement("div");
modal.id = "upload-modal";
modal.className = "modal";
modal.innerHTML = `
<div class="modal-content">
<div class="modal-header">
<h3>Upload Images</h3>
<span class="close" onclick="this.closest('.modal').style.display='none'">&times;</span>
</div>
<div class="modal-body">
<div class="upload-area" id="upload-area">
<div class="upload-content">
<div class="upload-icon">📤</div>
<h4>Drag & Drop images here</h4>
<p>or click to select files</p>
<input type="file" id="file-input" multiple accept="image/*" style="display: none;">
</div>
</div>
<div class="upload-preview" id="upload-preview"></div>
<div class="upload-actions">
<button class="btn btn-secondary" onclick="this.closest('.modal').style.display='none'">Cancel</button>
<button class="btn btn-primary" onclick="imageManager.processUpload()">Upload Images</button>
</div>
</div>
</div>
`;
// Setup drag and drop
const uploadArea = modal.querySelector("#upload-area");
const fileInput = modal.querySelector("#file-input");
uploadArea.addEventListener("click", () => fileInput.click());
uploadArea.addEventListener("dragover", (e) => {
e.preventDefault();
uploadArea.classList.add("drag-over");
});
uploadArea.addEventListener("dragleave", () => {
uploadArea.classList.remove("drag-over");
});
uploadArea.addEventListener("drop", (e) => {
e.preventDefault();
uploadArea.classList.remove("drag-over");
this.handleFileSelect(e.dataTransfer.files);
});
fileInput.addEventListener("change", (e) => {
this.handleFileSelect(e.target.files);
});
return modal;
}
handleFileSelect(files) {
const preview = document.getElementById("upload-preview");
preview.innerHTML = "";
Array.from(files).forEach((file) => {
if (file.type.startsWith("image/")) {
const reader = new FileReader();
reader.onload = (e) => {
const imageDiv = document.createElement("div");
imageDiv.className = "upload-preview-item";
imageDiv.innerHTML = `
<img src="${e.target.result}" alt="${file.name}">
<div class="upload-preview-info">
<span class="upload-filename">${file.name}</span>
<span class="upload-filesize">${this.formatFileSize(
file.size
)}</span>
</div>
<button class="remove-upload-btn" onclick="this.parentElement.remove()">×</button>
`;
preview.appendChild(imageDiv);
};
reader.readAsDataURL(file);
}
});
}
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];
}
async processUpload() {
const fileInput = document.getElementById("file-input");
const files = fileInput.files;
if (files.length === 0) {
this.dashboard.showMessage("Please select files to upload", "error");
return;
}
try {
this.dashboard.showMessage("Uploading images...", "info");
const uploadedImages = await this.uploadImages(files);
// Add to images list
uploadedImages.forEach((imagePath) => {
const fileName = this.extractFileName(imagePath);
this.images.push({
path: imagePath,
name: fileName,
productId: null,
productName: "Unassigned",
size: "Unknown",
uploadDate: new Date().toISOString(),
});
});
this.renderImages();
document.getElementById("upload-modal").style.display = "none";
this.dashboard.showMessage(
`Successfully uploaded ${uploadedImages.length} image(s)!`,
"success"
);
} catch (error) {
this.dashboard.showMessage(
"Error uploading images: " + error.message,
"error"
);
}
}
async uploadImages(files) {
const uploadedImages = [];
for (const file of files) {
if (file.type.startsWith("image/")) {
// In a real implementation, you'd upload to a server
const filename = `uploaded_${Date.now()}_${file.name}`;
const imagePath = `assets/images/products/${filename}`;
uploadedImages.push(imagePath);
console.log(`Would upload: ${file.name} to ${imagePath}`);
}
}
return uploadedImages;
}
viewImage(imagePath) {
// Create image viewer modal
const viewer = document.createElement("div");
viewer.className = "modal image-viewer";
viewer.innerHTML = `
<div class="modal-content image-viewer-content">
<div class="modal-header">
<h3>Image Viewer</h3>
<span class="close" onclick="this.closest('.modal').remove()">&times;</span>
</div>
<div class="modal-body">
<img src="${imagePath}" alt="Full size image" style="max-width: 100%; max-height: 70vh; object-fit: contain;">
</div>
</div>
`;
document.body.appendChild(viewer);
viewer.style.display = "block";
}
renameImage(imagePath) {
const currentName = this.extractFileName(imagePath);
const newName = prompt("Enter new name for the image:", currentName);
if (newName && newName !== currentName) {
// In a real implementation, you'd rename the file on the server
console.log(`Would rename ${imagePath} to ${newName}`);
this.dashboard.showMessage(
"Image rename functionality would be implemented here",
"info"
);
}
}
async deleteImage(imagePath) {
if (
confirm(
"Are you sure you want to delete this image? This action cannot be undone."
)
) {
try {
// Check if image is used by any products
const productsUsingImage =
this.dashboard.productManager.products.filter(
(product) => product.images && product.images.includes(imagePath)
);
if (productsUsingImage.length > 0) {
this.dashboard.showMessage(
`Cannot delete image because it's used by ${productsUsingImage.length} product(s). Please remove it from the products first.`,
"error"
);
return;
}
// Remove from images list
this.images = this.images.filter((img) => img.path !== imagePath);
// In a real implementation, you'd delete from server
console.log(`Would delete image: ${imagePath}`);
this.renderImages();
this.dashboard.showMessage("Image deleted successfully!", "success");
} catch (error) {
this.dashboard.showMessage(
"Error deleting image: " + error.message,
"error"
);
}
}
}
}
// Make ImageManager available globally
window.ImageManager = ImageManager;