diff --git a/src/actions/ai-import.ts b/src/actions/ai-import.ts index 33ebf9f..a062d87 100644 --- a/src/actions/ai-import.ts +++ b/src/actions/ai-import.ts @@ -258,11 +258,16 @@ function fallbackParse( stops: stopKeywords, }; + const escapeRegex = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const keywordPatterns: Record = {}; + for (const [etype, kws] of Object.entries(keywordMaps)) { + keywordPatterns[etype] = new RegExp(kws.map(escapeRegex).join("|")); + } + for (const header of h) { - for (const [etype, keywords] of Object.entries(keywordMaps)) { - for (const kw of keywords) { - if (header.includes(kw)) typeScores[etype] = (typeScores[etype] ?? 0) + 1; - } + for (const [etype, pattern] of Object.entries(keywordPatterns)) { + const matches = header.match(pattern); + if (matches) typeScores[etype] = (typeScores[etype] ?? 0) + matches.length; } } @@ -309,10 +314,15 @@ function fallbackParse( notes: ["notes", "note", "special_instructions", "comments", "memo", "instruction"], }; + const semanticPatterns: Record = {}; + for (const [field, kws] of Object.entries(semanticMap)) { + semanticPatterns[field] = new RegExp(kws.map(escapeRegex).join("|")); + } + for (let i = 0; i < h.length; i++) { const header = h[i]; - for (const [field, keywords] of Object.entries(semanticMap)) { - if (keywords.some((kw) => header.includes(kw))) { + for (const [field, pattern] of Object.entries(semanticPatterns)) { + if (pattern.test(header)) { columnMappings[headers[i]] = field; } } diff --git a/src/app/admin/launch-checklist/page.tsx b/src/app/admin/launch-checklist/page.tsx index 133aa9f..5d1a2a3 100644 --- a/src/app/admin/launch-checklist/page.tsx +++ b/src/app/admin/launch-checklist/page.tsx @@ -122,13 +122,13 @@ export default function LaunchChecklistPage() {
setSelectedCart(null)}> +
e.stopPropagation()}>
@@ -246,7 +250,7 @@ export default function AbandonedCartDashboard({ brandId }: Props) { )}
-
+ )} ); diff --git a/src/components/admin/AdminSidebar.tsx b/src/components/admin/AdminSidebar.tsx index 1fba17b..102cba0 100644 --- a/src/components/admin/AdminSidebar.tsx +++ b/src/components/admin/AdminSidebar.tsx @@ -191,9 +191,10 @@ export default function AdminSidebar({ * future iteration hides Harvest Reach for some role, the entire group * header goes away rather than rendering an empty section. */ + const visibleItemSet = new Set(visibleItems); const visibleGroups: NavGroup[] = []; for (const group of NAV_GROUPS) { - const items = group.items.filter((item) => visibleItems.includes(item)); + const items = group.items.filter((item) => visibleItemSet.has(item)); if (items.length > 0) { visibleGroups.push({ ...group, items }); } diff --git a/src/components/admin/CardList.tsx b/src/components/admin/CardList.tsx index 6484236..b5e0a9b 100644 --- a/src/components/admin/CardList.tsx +++ b/src/components/admin/CardList.tsx @@ -7,7 +7,7 @@ interface CardListProps { export function CardList({ children, ariaLabel }: CardListProps) { return ( -