Initial commit: KHY Admin project
This commit is contained in:
commit
d3403cb5e2
65 changed files with 12739 additions and 0 deletions
728
admin.html
Normal file
728
admin.html
Normal file
|
|
@ -0,0 +1,728 @@
|
|||
<!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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue