feat: Implement server-side category and product search via WebSockets, replacing client-side filtering with debounced input and dynamic tree expansion based on server results.

This commit is contained in:
sebseb7
2025-11-24 10:02:35 +01:00
parent d0b8183738
commit 9bf5d93d94
4 changed files with 239 additions and 122 deletions

View File

@@ -0,0 +1,73 @@
import fs from 'fs/promises';
import path from 'path';
export async function findMatches(query, cacheDir) {
if (!query || !query.trim()) return [];
const terms = query.toLowerCase().split(/\s+/).filter(t => t);
// Load category tree
const treePath = path.join(cacheDir, 'category_tree.json');
let tree = [];
try {
const treeData = await fs.readFile(treePath, 'utf-8');
tree = JSON.parse(treeData);
} catch (e) {
console.error("Failed to load category tree for search", e);
return [];
}
const matchingCategoryIds = new Set();
// Helper to check text match
const isMatch = (text) => {
if (!text) return false;
const lower = text.toLowerCase();
return terms.every(t => lower.includes(t));
};
// Flatten tree to linear list for easier iteration
const queue = [...tree];
const nodes = [];
while (queue.length > 0) {
const node = queue.shift();
nodes.push(node);
if (node.children) {
queue.push(...node.children);
}
}
// Process in chunks to avoid too many open files
const CHUNK_SIZE = 50;
for (let i = 0; i < nodes.length; i += CHUNK_SIZE) {
const chunk = nodes.slice(i, i + CHUNK_SIZE);
await Promise.all(chunk.map(async (node) => {
let nodeMatches = false;
// Check category name
if (isMatch(node.cName)) {
nodeMatches = true;
} else {
// Check products
try {
const prodPath = path.join(cacheDir, 'products', `category_${node.kKategorie}.json`);
// Check if file exists before reading to avoid throwing too many errors
// Actually readFile throws ENOENT which is fine
const prodData = await fs.readFile(prodPath, 'utf-8');
const products = JSON.parse(prodData);
if (products.some(p => isMatch(p.cName))) {
nodeMatches = true;
}
} catch (e) {
// Ignore missing files
}
}
if (nodeMatches) {
matchingCategoryIds.add(node.kKategorie);
}
}));
}
return Array.from(matchingCategoryIds);
}