338 lines
11 KiB
JavaScript
338 lines
11 KiB
JavaScript
// 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'">×</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()">×</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;
|