728 lines
28 KiB
HTML
728 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Product Management - KHY Admin</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<style>
|
|
.admin-container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
}
|
|
.product-card {
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
.form-group {
|
|
margin-bottom: 16px;
|
|
}
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 4px;
|
|
font-weight: 600;
|
|
}
|
|
.form-group input,
|
|
.form-group textarea,
|
|
.form-group select {
|
|
width: 100%;
|
|
padding: 8px;
|
|
border: 1px solid #d1d5db;
|
|
border-radius: 4px;
|
|
}
|
|
.btn {
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
border: none;
|
|
}
|
|
.btn-primary {
|
|
background: #3b82f6;
|
|
color: white;
|
|
}
|
|
.btn-danger {
|
|
background: #ef4444;
|
|
color: white;
|
|
}
|
|
.btn-success {
|
|
background: #10b981;
|
|
color: white;
|
|
}
|
|
.color-input {
|
|
width: 60px;
|
|
height: 40px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
}
|
|
.image-preview {
|
|
width: 100px;
|
|
height: 100px;
|
|
object-fit: cover;
|
|
border-radius: 4px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="bg-gray-50">
|
|
<div class="admin-container">
|
|
<h1 class="text-3xl font-bold mb-8">Product Management</h1>
|
|
|
|
<!-- Add New Product Form -->
|
|
<div class="bg-white p-6 rounded-lg shadow mb-8">
|
|
<h2 class="text-xl font-semibold mb-4">Add New Product</h2>
|
|
|
|
<!-- Preview Section -->
|
|
<div
|
|
id="previewSection"
|
|
class="hidden mb-6 p-4 bg-gray-50 rounded-lg border"
|
|
>
|
|
<h3 class="font-semibold mb-3">Preview</h3>
|
|
<div id="previewContent"></div>
|
|
</div>
|
|
|
|
<form id="productForm">
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div class="form-group">
|
|
<label>Product Name</label>
|
|
<input type="text" id="productName" required />
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Category</label>
|
|
<select id="productCategory" required>
|
|
<option value="seating">Seating</option>
|
|
<option value="tables">Tables</option>
|
|
<option value="storage">Storage</option>
|
|
<option value="workspace">Workspace</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Price</label>
|
|
<input type="number" id="productPrice" step="0.01" required />
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Model Number</label>
|
|
<input type="text" id="productModel" />
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Short Description</label>
|
|
<textarea id="productDescription" rows="2"></textarea>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Main Image URL</label>
|
|
<input
|
|
type="text"
|
|
id="productImage"
|
|
placeholder="assets/images/product.jpg"
|
|
/>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>In Stock</label>
|
|
<select id="productInStock">
|
|
<option value="true">Yes</option>
|
|
<option value="false">No</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Rating</label>
|
|
<input
|
|
type="number"
|
|
id="productRating"
|
|
step="0.1"
|
|
min="0"
|
|
max="5"
|
|
value="4.0"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<h3 class="font-semibold mb-2">Available Sizes</h3>
|
|
<div id="sizesContainer">
|
|
<div class="flex gap-2 mb-2">
|
|
<input
|
|
type="text"
|
|
placeholder="Size (e.g., S, M, L)"
|
|
class="size-input"
|
|
/>
|
|
<button
|
|
type="button"
|
|
onclick="removeSize(this)"
|
|
class="btn btn-danger"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<button type="button" onclick="addSize()" class="btn btn-primary">
|
|
Add Size
|
|
</button>
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<h3 class="font-semibold mb-2">Available Colors</h3>
|
|
<div id="colorsContainer">
|
|
<div class="flex gap-2 mb-2 items-center">
|
|
<input
|
|
type="text"
|
|
placeholder="Color Name"
|
|
class="color-name"
|
|
/>
|
|
<input type="color" class="color-input" value="#000000" />
|
|
<button
|
|
type="button"
|
|
onclick="removeColor(this)"
|
|
class="btn btn-danger"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<button type="button" onclick="addColor()" class="btn btn-primary">
|
|
Add Color
|
|
</button>
|
|
</div>
|
|
|
|
<div class="mt-6 flex gap-4">
|
|
<button type="submit" class="btn btn-success">Add Product</button>
|
|
<button
|
|
type="button"
|
|
onclick="previewProduct()"
|
|
class="btn btn-primary"
|
|
>
|
|
Preview Product
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onclick="cancelEdit()"
|
|
class="btn btn-danger hidden"
|
|
id="cancelEditBtn"
|
|
>
|
|
Cancel Edit
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Products List -->
|
|
<div class="bg-white p-6 rounded-lg shadow">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h2 class="text-xl font-semibold">Current Products</h2>
|
|
<div class="flex gap-2">
|
|
<button onclick="previewWebsite()" class="btn btn-primary">
|
|
👀 Preview Website
|
|
</button>
|
|
<button onclick="downloadProductsJSON()" class="btn btn-primary">
|
|
Download products.json
|
|
</button>
|
|
<button onclick="deployToProduction()" class="btn btn-success">
|
|
🚀 Copy to Main Website
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="productsList"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let products = [];
|
|
|
|
// Load products on page load
|
|
async function loadProducts() {
|
|
try {
|
|
const response = await fetch("data/products.json");
|
|
const data = await response.json();
|
|
products = data.products;
|
|
displayProducts();
|
|
} catch (error) {
|
|
console.error("Error loading products:", error);
|
|
alert("Error loading products. Please refresh the page.");
|
|
}
|
|
}
|
|
|
|
// Display products
|
|
function displayProducts() {
|
|
const container = document.getElementById("productsList");
|
|
container.innerHTML = "";
|
|
|
|
products.forEach((product, index) => {
|
|
const productCard = document.createElement("div");
|
|
productCard.className = "product-card";
|
|
productCard.innerHTML = `
|
|
<div class="flex justify-between items-start">
|
|
<div class="flex gap-4">
|
|
<img src="${product.image}" alt="${product.name}" class="image-preview" onerror="this.src='assets/images/placeholder.jpg'">
|
|
<div>
|
|
<h3 class="font-semibold">${product.name}</h3>
|
|
<p class="text-gray-600">${product.category} • $${product.price}</p>
|
|
<p class="text-sm text-gray-500">${product.description}</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<button onclick="editProduct(${index})" class="btn btn-primary">Edit</button>
|
|
<button onclick="deleteProduct(${index})" class="btn btn-danger">Delete</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
container.appendChild(productCard);
|
|
});
|
|
}
|
|
|
|
// Add new product or update existing
|
|
document
|
|
.getElementById("productForm")
|
|
.addEventListener("submit", function (e) {
|
|
e.preventDefault();
|
|
|
|
const sizes = Array.from(document.querySelectorAll(".size-input"))
|
|
.map((input) => input.value)
|
|
.filter((size) => size.trim());
|
|
const colors = Array.from(document.querySelectorAll(".color-name"))
|
|
.map((input, index) => {
|
|
const colorInput =
|
|
input.parentElement.querySelector(".color-input");
|
|
return {
|
|
name: input.value,
|
|
value: colorInput.value,
|
|
selected: index === 0,
|
|
};
|
|
})
|
|
.filter((color) => color.name.trim());
|
|
|
|
const productData = {
|
|
name: document.getElementById("productName").value,
|
|
description: document.getElementById("productDescription").value,
|
|
image: document.getElementById("productImage").value,
|
|
alt: document.getElementById("productName").value,
|
|
category: document.getElementById("productCategory").value,
|
|
modelNo: document.getElementById("productModel").value,
|
|
tags: [document.getElementById("productCategory").value],
|
|
sizes: sizes,
|
|
colors: colors,
|
|
selectedSize: sizes[0] || "M",
|
|
selectedColor: colors[0]?.name || "Default",
|
|
price: parseFloat(document.getElementById("productPrice").value),
|
|
originalPrice: parseFloat(
|
|
document.getElementById("productPrice").value
|
|
),
|
|
rating: document.getElementById("productRating").value,
|
|
reviews: 0,
|
|
inStock: document.getElementById("productInStock").value === "true",
|
|
images: [document.getElementById("productImage").value],
|
|
descriptionLong: [
|
|
document.getElementById("productDescription").value,
|
|
],
|
|
additionalInformation: {
|
|
Material: "Premium materials",
|
|
Dimensions: "See size options",
|
|
Warranty: "3 years",
|
|
},
|
|
reviewsCount: 0,
|
|
galleryPairs: [
|
|
{
|
|
left: document.getElementById("productImage").value,
|
|
right: document.getElementById("productImage").value,
|
|
},
|
|
],
|
|
dimensions: "See size options",
|
|
salesPackage: "1 unit",
|
|
configuration: "Standard",
|
|
fillingMaterial: "High-density foam",
|
|
finishType: "Premium finish",
|
|
adjustableHeadrest: "No",
|
|
maxLoadCapacity: "150kg",
|
|
originOfManufacture: "Ghana",
|
|
weight: "25kg",
|
|
seatHeight: "45cm",
|
|
legHeight: "10cm",
|
|
warrantyServiceType: "Standard warranty service",
|
|
coveredInWarranty: "Manufacturing defects",
|
|
notCoveredInWarranty: "Wear and tear not covered",
|
|
};
|
|
|
|
const form = document.getElementById("productForm");
|
|
const editIndex = form.dataset.editIndex;
|
|
|
|
if (editIndex !== undefined) {
|
|
// Update existing product
|
|
productData.id = products[editIndex].id;
|
|
products[editIndex] = productData;
|
|
alert("Product updated successfully!");
|
|
|
|
// Reset form to add mode
|
|
form.dataset.editIndex = "";
|
|
form.querySelector("button[type='submit']").textContent =
|
|
"Add Product";
|
|
} else {
|
|
// Add new product
|
|
productData.id = Math.max(...products.map((p) => p.id)) + 1;
|
|
products.push(productData);
|
|
alert("Product added successfully!");
|
|
}
|
|
|
|
displayProducts();
|
|
document.getElementById("productForm").reset();
|
|
hidePreview();
|
|
});
|
|
|
|
// Helper functions
|
|
function addSize() {
|
|
const container = document.getElementById("sizesContainer");
|
|
const div = document.createElement("div");
|
|
div.className = "flex gap-2 mb-2";
|
|
div.innerHTML = `
|
|
<input type="text" placeholder="Size (e.g., S, M, L)" class="size-input">
|
|
<button type="button" onclick="removeSize(this)" class="btn btn-danger">Remove</button>
|
|
`;
|
|
container.appendChild(div);
|
|
}
|
|
|
|
function removeSize(button) {
|
|
button.parentElement.remove();
|
|
}
|
|
|
|
function addColor() {
|
|
const container = document.getElementById("colorsContainer");
|
|
const div = document.createElement("div");
|
|
div.className = "flex gap-2 mb-2 items-center";
|
|
div.innerHTML = `
|
|
<input type="text" placeholder="Color Name" class="color-name">
|
|
<input type="color" class="color-input" value="#000000">
|
|
<button type="button" onclick="removeColor(this)" class="btn btn-danger">Remove</button>
|
|
`;
|
|
container.appendChild(div);
|
|
}
|
|
|
|
function removeColor(button) {
|
|
button.parentElement.remove();
|
|
}
|
|
|
|
function editProduct(index) {
|
|
const product = products[index];
|
|
|
|
// Populate form with existing product data
|
|
document.getElementById("productName").value = product.name;
|
|
document.getElementById("productDescription").value =
|
|
product.description;
|
|
document.getElementById("productImage").value = product.image;
|
|
document.getElementById("productCategory").value = product.category;
|
|
document.getElementById("productPrice").value = product.price;
|
|
document.getElementById("productModel").value = product.modelNo || "";
|
|
document.getElementById("productInStock").value =
|
|
product.inStock.toString();
|
|
document.getElementById("productRating").value = product.rating;
|
|
|
|
// Clear existing sizes and colors
|
|
document.getElementById("sizesContainer").innerHTML = "";
|
|
document.getElementById("colorsContainer").innerHTML = "";
|
|
|
|
// Add existing sizes
|
|
product.sizes.forEach((size) => {
|
|
addSize();
|
|
const sizeInputs = document.querySelectorAll(".size-input");
|
|
sizeInputs[sizeInputs.length - 1].value = size;
|
|
});
|
|
|
|
// Add existing colors
|
|
product.colors.forEach((color) => {
|
|
addColor();
|
|
const colorInputs = document.querySelectorAll(".color-name");
|
|
const colorPickers = document.querySelectorAll(".color-input");
|
|
colorInputs[colorInputs.length - 1].value = color.name;
|
|
colorPickers[colorPickers.length - 1].value = color.value;
|
|
});
|
|
|
|
// Change form to edit mode
|
|
const form = document.getElementById("productForm");
|
|
form.dataset.editIndex = index;
|
|
form.querySelector("button[type='submit']").textContent =
|
|
"Update Product";
|
|
document.getElementById("cancelEditBtn").classList.remove("hidden");
|
|
|
|
// Scroll to form
|
|
form.scrollIntoView({ behavior: "smooth" });
|
|
|
|
// Show preview
|
|
showPreview(product);
|
|
}
|
|
|
|
function deleteProduct(index) {
|
|
const product = products[index];
|
|
const confirmMessage = `Are you sure you want to delete "${product.name}"?\n\nThis action cannot be undone.`;
|
|
|
|
if (confirm(confirmMessage)) {
|
|
products.splice(index, 1);
|
|
displayProducts();
|
|
alert(`"${product.name}" has been deleted successfully!`);
|
|
}
|
|
}
|
|
|
|
function previewProduct() {
|
|
const sizes = Array.from(document.querySelectorAll(".size-input"))
|
|
.map((input) => input.value)
|
|
.filter((size) => size.trim());
|
|
const colors = Array.from(document.querySelectorAll(".color-name"))
|
|
.map((input, index) => {
|
|
const colorInput =
|
|
input.parentElement.querySelector(".color-input");
|
|
return {
|
|
name: input.value,
|
|
value: colorInput.value,
|
|
selected: index === 0,
|
|
};
|
|
})
|
|
.filter((color) => color.name.trim());
|
|
|
|
const previewProduct = {
|
|
name: document.getElementById("productName").value || "Product Name",
|
|
description:
|
|
document.getElementById("productDescription").value ||
|
|
"Product description",
|
|
image:
|
|
document.getElementById("productImage").value ||
|
|
"assets/images/placeholder.jpg",
|
|
category:
|
|
document.getElementById("productCategory").value || "seating",
|
|
price: document.getElementById("productPrice").value || "0",
|
|
modelNo: document.getElementById("productModel").value || "",
|
|
sizes: sizes,
|
|
colors: colors,
|
|
inStock: document.getElementById("productInStock").value === "true",
|
|
rating: document.getElementById("productRating").value || "4.0",
|
|
};
|
|
|
|
showPreview(previewProduct);
|
|
}
|
|
|
|
function showPreview(product) {
|
|
const previewSection = document.getElementById("previewSection");
|
|
const previewContent = document.getElementById("previewContent");
|
|
|
|
previewContent.innerHTML = `
|
|
<div class="flex gap-4">
|
|
<img src="${product.image}" alt="${
|
|
product.name
|
|
}" class="w-24 h-24 object-cover rounded" onerror="this.src='assets/images/placeholder.jpg'">
|
|
<div class="flex-1">
|
|
<h4 class="font-semibold text-lg">${product.name}</h4>
|
|
<p class="text-gray-600">${product.category} • $${
|
|
product.price
|
|
}</p>
|
|
<p class="text-sm text-gray-500 mb-2">${product.description}</p>
|
|
<div class="text-xs text-gray-400">
|
|
<p><strong>Model:</strong> ${product.modelNo || "N/A"}</p>
|
|
<p><strong>Sizes:</strong> ${
|
|
product.sizes.length > 0 ? product.sizes.join(", ") : "None"
|
|
}</p>
|
|
<p><strong>Colors:</strong> ${
|
|
product.colors.length > 0
|
|
? product.colors.map((c) => c.name).join(", ")
|
|
: "None"
|
|
}</p>
|
|
<p><strong>In Stock:</strong> ${
|
|
product.inStock ? "Yes" : "No"
|
|
}</p>
|
|
<p><strong>Rating:</strong> ${product.rating}/5</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
previewSection.classList.remove("hidden");
|
|
previewSection.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
}
|
|
|
|
function hidePreview() {
|
|
const previewSection = document.getElementById("previewSection");
|
|
previewSection.classList.add("hidden");
|
|
}
|
|
|
|
function cancelEdit() {
|
|
const form = document.getElementById("productForm");
|
|
form.dataset.editIndex = "";
|
|
form.querySelector("button[type='submit']").textContent = "Add Product";
|
|
document.getElementById("cancelEditBtn").classList.add("hidden");
|
|
document.getElementById("productForm").reset();
|
|
hidePreview();
|
|
}
|
|
|
|
function downloadProductsJSON() {
|
|
const data = {
|
|
products: products,
|
|
categories: [
|
|
{
|
|
id: "seating",
|
|
name: "Seating",
|
|
description:
|
|
"Office chairs, lounge chairs, and seating solutions",
|
|
},
|
|
{
|
|
id: "tables",
|
|
name: "Tables",
|
|
description: "Conference tables, workstations, and dining tables",
|
|
},
|
|
{
|
|
id: "storage",
|
|
name: "Storage",
|
|
description:
|
|
"Storage units, lockers, and organizational solutions",
|
|
},
|
|
{
|
|
id: "workspace",
|
|
name: "Workspace",
|
|
description: "Pods, phone booths, and collaborative spaces",
|
|
},
|
|
],
|
|
pagination: {
|
|
itemsPerPage: 16,
|
|
totalItems: products.length,
|
|
currentPage: 1,
|
|
totalPages: Math.ceil(products.length / 16),
|
|
},
|
|
};
|
|
|
|
const blob = new Blob([JSON.stringify(data, null, 2)], {
|
|
type: "application/json",
|
|
});
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement("a");
|
|
a.href = url;
|
|
a.download = "products.json";
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
|
|
alert(`Downloaded products.json with ${products.length} products!`);
|
|
}
|
|
|
|
function previewWebsite() {
|
|
const baseUrl =
|
|
window.location.origin +
|
|
window.location.pathname.replace("admin.html", "");
|
|
|
|
const previewMessage = `Preview Website\n\nThis will help you preview how your products will look on the website.\n\nChoose your preferred method:\n\nOption 1: Auto-start server (Recommended)\n- Click OK to get instructions for running: npm run preview\n- This will start the server and open all preview pages automatically\n\nOption 2: Open preview pages now\n- Click Cancel to open preview pages in current browser\n- Make sure you have a server running first`;
|
|
|
|
if (confirm(previewMessage)) {
|
|
// Show instructions for auto-start
|
|
alert(
|
|
`🚀 Auto-Start Preview Server\n\nTo automatically start the server and open preview pages:\n\n1. Open Terminal/Command Prompt\n2. Navigate to the admin folder\n3. Run: npm run preview\n\nThis will:\n- Start the local server\n- Open admin dashboard\n- Open homepage preview\n- Open product catalog preview\n- Open product details preview\n\nAll in one command! 🎉`
|
|
);
|
|
} else {
|
|
// Open preview pages in current browser
|
|
const pages = [
|
|
{ url: "index.html", name: "Homepage" },
|
|
{ url: "product-catalog.html", name: "Product Catalog" },
|
|
{ url: "product-detail.html", name: "Product Details" },
|
|
];
|
|
|
|
pages.forEach((page, index) => {
|
|
setTimeout(() => {
|
|
window.open(page.url, `_blank`);
|
|
}, index * 500); // Stagger opening to avoid popup blockers
|
|
});
|
|
|
|
// Show helpful message
|
|
setTimeout(() => {
|
|
alert(
|
|
`👀 Preview Pages Opened\n\nOpened in new tabs:\n- Homepage\n- Product Catalog\n- Product Details\n\nIf tabs didn't open, check your popup blocker settings.\n\n💡 For the best experience, run: npm run preview`
|
|
);
|
|
}, 2000);
|
|
}
|
|
}
|
|
|
|
function deployToProduction() {
|
|
const confirmMessage = `Copy to Main Website\n\nThis will copy your updated product data to the main KHY website.\n\nAre you sure you want to proceed?\n\nThis will:\n- Stop the preview server (if running)\n- Copy admin/data/products.json → ../data/products.json\n- Copy admin/assets/images/ → ../assets/images/\n- Create a backup of current main website data\n- Update the main KHY website immediately\n\nMake sure you've previewed your changes first!`;
|
|
|
|
if (confirm(confirmMessage)) {
|
|
// Show deployment instructions
|
|
alert(
|
|
`Copy Instructions\n\nTo copy your changes to the main KHY website:\n\n1. Open Terminal/Command Prompt\n2. Navigate to the admin folder\n3. Run: npm run deploy\n\nThis will:\n- Automatically stop the preview server\n- Copy admin/data/products.json → main website data/products.json\n- Copy admin/assets/images/ → main website assets/images/\n\nYour main KHY website will be updated immediately!\n\nThe preview server will be automatically stopped during deployment.\n\nNote: If this is your first time, run 'npm run setup' first to configure the deploy paths.`
|
|
);
|
|
}
|
|
}
|
|
|
|
// Server management
|
|
let previewTabs = [];
|
|
|
|
// Function to kill preview server
|
|
function killPreviewServer() {
|
|
// This would need to be implemented with a backend endpoint
|
|
// For now, we'll show instructions
|
|
alert(
|
|
`Stop Preview Server\n\nTo stop the preview server:\n\n1. Open Terminal/Command Prompt\n2. Navigate to the admin folder\n3. Run: npm run preview:kill\n\nOr press Ctrl+C in the terminal where the server is running.`
|
|
);
|
|
}
|
|
|
|
// Function to track preview tabs
|
|
function trackPreviewTab(tab) {
|
|
previewTabs.push(tab);
|
|
|
|
// Check if tab is closed
|
|
const checkClosed = setInterval(() => {
|
|
if (tab.closed) {
|
|
previewTabs = previewTabs.filter((t) => t !== tab);
|
|
clearInterval(checkClosed);
|
|
|
|
// If no preview tabs are open, offer to kill server
|
|
if (previewTabs.length === 0) {
|
|
setTimeout(() => {
|
|
if (
|
|
confirm(
|
|
`All Preview Tabs Closed\n\nAll preview tabs have been closed.\n\nWould you like to stop the preview server?\n\nThis will free up the port for other uses.`
|
|
)
|
|
) {
|
|
killPreviewServer();
|
|
}
|
|
}, 1000);
|
|
}
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
// Enhanced preview function with tab tracking
|
|
function previewWebsiteWithTracking() {
|
|
const baseUrl =
|
|
window.location.origin +
|
|
window.location.pathname.replace("admin.html", "");
|
|
|
|
const previewMessage = `Preview Website\n\nThis will help you preview how your products will look on the website.\n\nChoose your preferred method:\n\nOption 1: Auto-start server (Recommended)\n- Click OK to get instructions for running: npm run preview\n- This will start the server and open all preview pages automatically\n\nOption 2: Open preview pages now\n- Click Cancel to open preview pages in current browser\n- Make sure you have a server running first`;
|
|
|
|
if (confirm(previewMessage)) {
|
|
// Show instructions for auto-start
|
|
alert(
|
|
`Auto-Start Preview Server\n\nTo automatically start the server and open preview pages:\n\n1. Open Terminal/Command Prompt\n2. Navigate to the admin folder\n3. Run: npm run preview\n\nThis will:\n- Start the local server\n- Open admin dashboard\n- Open homepage preview\n- Open product catalog preview\n- Open product details preview\n\nAll in one command!\n\nThe server will automatically stop when you close preview tabs or deploy changes.`
|
|
);
|
|
} else {
|
|
// Open preview pages in current browser with tracking
|
|
const pages = [
|
|
{ url: "index.html", name: "Homepage" },
|
|
{ url: "product-catalog.html", name: "Product Catalog" },
|
|
{ url: "product-detail.html", name: "Product Details" },
|
|
];
|
|
|
|
pages.forEach((page, index) => {
|
|
setTimeout(() => {
|
|
const tab = window.open(page.url, `_blank`);
|
|
if (tab) {
|
|
trackPreviewTab(tab);
|
|
}
|
|
}, index * 500); // Stagger opening to avoid popup blockers
|
|
});
|
|
|
|
// Show helpful message
|
|
setTimeout(() => {
|
|
alert(
|
|
`Preview Pages Opened\n\nOpened in new tabs:\n- Homepage\n- Product Catalog\n- Product Details\n\nIf tabs didn't open, check your popup blocker settings.\n\nFor the best experience, run: npm run preview\n\nThe server will be automatically stopped when you close all preview tabs.`
|
|
);
|
|
}, 2000);
|
|
}
|
|
}
|
|
|
|
// Override the original preview function
|
|
window.previewWebsite = previewWebsiteWithTracking;
|
|
|
|
// Load products when page loads
|
|
loadProducts();
|
|
</script>
|
|
</body>
|
|
</html>
|