| @@ -28,14 +28,35 @@ | ||
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | export function getIconOptions(): IconOption[] { |
| 31 | 31 | const m = yatraIconsManifest as Record<string, YatraManifestEntry>; |
| 32 | - return Object.entries(m).map(([name, meta]) => ({ | |
| 33 | - name, | |
| 34 | - label: meta.label, | |
| 35 | - category: meta.category, | |
| 36 | - svg: meta.svg, | |
| 37 | - })); | |
| 32 | + // Some manifest entries only carry `svg` (sync script left them without | |
| 33 | + // label/category). Without defensive defaults, IconPicker's search filter | |
| 34 | + // calls `.toLowerCase()` on undefined and crashes the whole panel. | |
| 35 | + // Derive a readable label from the slug ("hot-air-balloon" → "Hot Air | |
| 36 | + // Balloon") and fall back to a "general" bucket for the category so the | |
| 37 | + // search and category-filter UI still works. | |
| 38 | + const slugToLabel = (slug: string): string => | |
| 39 | + slug | |
| 40 | + .split(/[-_\s]+/) | |
| 41 | + .filter(Boolean) | |
| 42 | + .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) | |
| 43 | + .join(" "); | |
| 44 | + return Object.entries(m).map(([name, meta]) => { | |
| 45 | + const safeMeta = (meta || {}) as Partial<YatraManifestEntry>; | |
| 46 | + return { | |
| 47 | + name, | |
| 48 | + label: | |
| 49 | + typeof safeMeta.label === "string" && safeMeta.label.length > 0 | |
| 50 | + ? safeMeta.label | |
| 51 | + : slugToLabel(name), | |
| 52 | + category: | |
| 53 | + typeof safeMeta.category === "string" && safeMeta.category.length > 0 | |
| 54 | + ? safeMeta.category | |
| 55 | + : "general", | |
| 56 | + svg: safeMeta.svg || "", | |
| 57 | + }; | |
| 58 | + }); | |
| 38 | 59 | } |
| 39 | 60 | |
| 40 | 61 | export function getYatraIconSvg(slug: string): string | null { |
| 41 | 62 | const m = yatraIconsManifest as Record<string, YatraManifestEntry>; |