diff --git a/backend/src/routes/intelligence.ts b/backend/src/routes/intelligence.ts index ff48f4ef..e877a1e6 100644 --- a/backend/src/routes/intelligence.ts +++ b/backend/src/routes/intelligence.ts @@ -21,18 +21,30 @@ router.use(authMiddleware); */ router.get('/brands', async (req: Request, res: Response) => { try { - const { limit = '500', offset = '0', state } = req.query; + const { limit = '500', offset = '0', state, search } = req.query; const limitNum = Math.min(parseInt(limit as string, 10), 1000); const offsetNum = parseInt(offset as string, 10); - // Build WHERE clause based on state filter - let stateFilter = ''; + // Build WHERE clause based on filters + const conditions: string[] = ["sp.brand_name_raw IS NOT NULL AND sp.brand_name_raw != ''"]; const params: any[] = [limitNum, offsetNum]; + let paramIndex = 3; + if (state && state !== 'all') { - stateFilter = 'AND d.state = $3'; + conditions.push(`d.state = $${paramIndex}`); params.push(state); + paramIndex++; } + // Server-side search - case-insensitive partial match + if (search && typeof search === 'string' && search.trim()) { + conditions.push(`sp.brand_name_raw ILIKE $${paramIndex}`); + params.push(`%${search.trim()}%`); + paramIndex++; + } + + const whereClause = conditions.join(' AND '); + const { rows } = await pool.query(` SELECT sp.brand_name_raw as brand_name, @@ -43,26 +55,22 @@ router.get('/brands', async (req: Request, res: Response) => { ROUND(AVG(sp.price_med) FILTER (WHERE sp.price_med > 0)::numeric, 2) as avg_price_med FROM store_products sp JOIN dispensaries d ON sp.dispensary_id = d.id - WHERE sp.brand_name_raw IS NOT NULL AND sp.brand_name_raw != '' - ${stateFilter} + WHERE ${whereClause} GROUP BY sp.brand_name_raw ORDER BY store_count DESC, sku_count DESC LIMIT $1 OFFSET $2 `, params); - // Get total count with same state filter - const countParams: any[] = []; - let countStateFilter = ''; - if (state && state !== 'all') { - countStateFilter = 'AND d.state = $1'; - countParams.push(state); - } + // Get total count with same filters (excluding limit/offset) + const countParams = params.slice(2); // Remove limit and offset + const countConditions = conditions.map((c, i) => + c.replace(/\$\d+/g, (match) => `$${parseInt(match.slice(1)) - 2}`) + ); const { rows: countRows } = await pool.query(` SELECT COUNT(DISTINCT sp.brand_name_raw) as total FROM store_products sp JOIN dispensaries d ON sp.dispensary_id = d.id - WHERE sp.brand_name_raw IS NOT NULL AND sp.brand_name_raw != '' - ${countStateFilter} + WHERE ${countConditions.join(' AND ')} `, countParams); res.json({ diff --git a/cannaiq/dist/index.html b/cannaiq/dist/index.html index 8bde23cc..bbf3c50c 100644 --- a/cannaiq/dist/index.html +++ b/cannaiq/dist/index.html @@ -7,7 +7,7 @@