fix: Findagram brands page crash and PWA icon errors

- Fix mapBrandForUI to use correct 'brand' field from API response
- Add null check in Brands.jsx filter to prevent crash on undefined names
- Fix BrandPenetrationService sps.brand_name -> sps.brand_name_raw
- Remove missing logo192.png and logo512.png from PWA manifest

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Kelly
2025-12-10 13:06:23 -07:00
parent 37cc8956c5
commit 53445fe72a
4 changed files with 13 additions and 21 deletions

View File

@@ -75,7 +75,7 @@ export class BrandPenetrationService {
DATE(sps.captured_at) AS date, DATE(sps.captured_at) AS date,
COUNT(DISTINCT sps.dispensary_id) AS dispensary_count COUNT(DISTINCT sps.dispensary_id) AS dispensary_count
FROM store_product_snapshots sps FROM store_product_snapshots sps
WHERE sps.brand_name = $1 WHERE sps.brand_name_raw = $1
AND sps.captured_at >= $2 AND sps.captured_at >= $2
AND sps.captured_at <= $3 AND sps.captured_at <= $3
AND sps.is_in_stock = TRUE AND sps.is_in_stock = TRUE
@@ -368,23 +368,23 @@ export class BrandPenetrationService {
const result = await this.pool.query(` const result = await this.pool.query(`
WITH start_counts AS ( WITH start_counts AS (
SELECT SELECT
brand_name, brand_name_raw AS brand_name,
COUNT(DISTINCT dispensary_id) AS dispensary_count COUNT(DISTINCT dispensary_id) AS dispensary_count
FROM store_product_snapshots FROM store_product_snapshots
WHERE captured_at >= $1 AND captured_at < $1 + INTERVAL '1 day' WHERE captured_at >= $1 AND captured_at < $1 + INTERVAL '1 day'
AND brand_name IS NOT NULL AND brand_name_raw IS NOT NULL
AND is_in_stock = TRUE AND is_in_stock = TRUE
GROUP BY brand_name GROUP BY brand_name_raw
), ),
end_counts AS ( end_counts AS (
SELECT SELECT
brand_name, brand_name_raw AS brand_name,
COUNT(DISTINCT dispensary_id) AS dispensary_count COUNT(DISTINCT dispensary_id) AS dispensary_count
FROM store_product_snapshots FROM store_product_snapshots
WHERE captured_at >= $2 - INTERVAL '1 day' AND captured_at <= $2 WHERE captured_at >= $2 - INTERVAL '1 day' AND captured_at <= $2
AND brand_name IS NOT NULL AND brand_name_raw IS NOT NULL
AND is_in_stock = TRUE AND is_in_stock = TRUE
GROUP BY brand_name GROUP BY brand_name_raw
) )
SELECT SELECT
COALESCE(sc.brand_name, ec.brand_name) AS brand_name, COALESCE(sc.brand_name, ec.brand_name) AS brand_name,

View File

@@ -7,16 +7,6 @@
"src": "favicon.ico", "src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16", "sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon" "type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
} }
], ],
"start_url": ".", "start_url": ".",

View File

@@ -373,10 +373,12 @@ export function mapCategoryForUI(apiCategory) {
* Map API brand to UI-compatible format * Map API brand to UI-compatible format
*/ */
export function mapBrandForUI(apiBrand) { export function mapBrandForUI(apiBrand) {
// API returns 'brand' field (see /api/v1/brands endpoint)
const brandName = apiBrand.brand || apiBrand.brand_name || '';
return { return {
id: apiBrand.brand_name, id: brandName,
name: apiBrand.brand_name, name: brandName,
slug: apiBrand.brand_name?.toLowerCase().replace(/\s+/g, '-'), slug: brandName ? brandName.toLowerCase().replace(/\s+/g, '-') : '',
logo: apiBrand.brand_logo_url || null, logo: apiBrand.brand_logo_url || null,
productCount: parseInt(apiBrand.product_count || 0, 10), productCount: parseInt(apiBrand.product_count || 0, 10),
dispensaryCount: parseInt(apiBrand.dispensary_count || 0, 10), dispensaryCount: parseInt(apiBrand.dispensary_count || 0, 10),

View File

@@ -27,7 +27,7 @@ const Brands = () => {
}, []); }, []);
const filteredBrands = brands.filter((brand) => const filteredBrands = brands.filter((brand) =>
brand.name.toLowerCase().includes(searchQuery.toLowerCase()) brand.name && brand.name.toLowerCase().includes(searchQuery.toLowerCase())
); );
// Group brands alphabetically // Group brands alphabetically