feat: Enhance product management by adding WebSocket support for real-time updates, implement product loading in categories, and improve caching for category products.

This commit is contained in:
sebseb7
2025-11-23 11:40:42 +01:00
parent 49246169db
commit 71910f84a2
4 changed files with 361 additions and 7 deletions

View File

@@ -117,6 +117,21 @@
border-radius: 8px;
text-align: center;
}
.category-products {
margin-top: 0.5rem;
padding-left: 4rem;
font-size: 0.9rem;
color: #555;
}
.product-item {
padding: 0.25rem 0;
border-bottom: 1px solid #eee;
}
.product-item:last-child {
border-bottom: none;
}
</style>
</head>
<body>
@@ -127,7 +142,32 @@
</div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io({
transports: ['websocket']
});
socket.on('connect', () => {
console.log('🔌 Connected to server via WebSocket');
});
socket.on('categoriesUpdated', () => {
console.log('🔄 Categories updated, reloading tree...');
loadCategories();
});
socket.on('categoryProductsUpdated', ({ id }) => {
console.log(`🔄 Products for category ${id} updated, reloading...`);
// Find the specific category element and reload its products
// Since we don't have easy access to instances, we could reload the whole tree
// or dispatch a custom event. For simplicity, we'll reload the tree for now
// but ideally we'd target the specific DOM element.
// Better approach: emit event that specific components can listen to
document.dispatchEvent(new CustomEvent('productsUpdated', { detail: { id } }));
});
async function loadCategories() {
try {
const response = await fetch('/api/categories');
@@ -194,6 +234,62 @@
header.appendChild(info);
div.appendChild(header);
// Products
const productsDiv = document.createElement('div');
productsDiv.className = 'category-products';
productsDiv.innerHTML = '<small>Loading products...</small>';
div.appendChild(productsDiv);
// Load products
const loadProducts = () => {
productsDiv.innerHTML = '<small>Loading products...</small>';
productsDiv.style.display = 'block';
fetch(`/api/categories/${category.kKategorie}/products`)
.then(res => res.ok ? res.json() : [])
.then(products => {
productsDiv.innerHTML = '';
if (products.length === 0) {
productsDiv.style.display = 'none';
return;
}
const ul = document.createElement('ul');
ul.style.listStyle = 'none';
products.slice(0, 3).forEach(p => {
const li = document.createElement('li');
li.className = 'product-item';
li.textContent = `📦 ${p.cName}`;
ul.appendChild(li);
});
if (products.length > 3) {
const more = document.createElement('li');
more.className = 'product-item';
more.style.fontStyle = 'italic';
more.textContent = `...and ${products.length - 3} more`;
ul.appendChild(more);
}
productsDiv.appendChild(ul);
})
.catch(() => {
productsDiv.style.display = 'none';
});
};
loadProducts();
// Listen for updates
const updateHandler = (e) => {
if (e.detail.id === category.kKategorie) {
console.log(`✨ refreshing products for category ${category.kKategorie}`);
loadProducts();
}
};
document.addEventListener('productsUpdated', updateHandler);
// Children
if (category.children && category.children.length > 0) {