/** * Icon Picker: Yatra library (icons.json / Lucide SVG) + Font Awesome 6 Free + image upload. */ import React, { useState, useCallback, useEffect, useMemo } from "react"; import { Upload, X, Search, Image as ImageLucide, Sparkles, Check, } from "lucide-react"; import { getIconOptions } from "../../lib/icons"; import { FA_FREE_SOLID_PICKER, FA_FREE_REGULAR_PICKER, } from "../../lib/fa-free-picker-icons"; import type { IconPickerValue, IconProvider, } from "../../lib/icon-picker-types"; export type { IconPickerValue, IconProvider, } from "../../lib/icon-picker-types"; import { __ } from "../../lib/i18n"; import { Button } from "./button"; import { Input } from "./input"; import { Badge } from "./badge"; import { Modal } from "./modal"; import { useWordPressMedia } from "../../hooks/useWordPressMedia"; const categoryLabels: Record = { activity: "Activities", travel: "Travel", food: "Food & Dining", accommodation: "Accommodation", transport: "Transportation", general: "General", media: "Media", }; interface IconPickerProps { value?: IconPickerValue | null; onChange: (value: IconPickerValue | null) => void; label?: string; helpText?: string; error?: string; required?: boolean; allowImageUpload?: boolean; allowIconSelection?: boolean; size?: "sm" | "md" | "lg"; className?: string; } export const IconPicker: React.FC = ({ value, onChange, label, helpText, error, required = false, allowImageUpload = true, allowIconSelection = true, size = "md", className = "", }) => { const [isOpen, setIsOpen] = useState(false); const [activeTab, setActiveTab] = useState<"icons" | "upload">("icons"); const [iconLibrary, setIconLibrary] = useState("yatra"); const [searchTerm, setSearchTerm] = useState(""); const [selectedCategory, setSelectedCategory] = useState("all"); const yatraIconOptions = useMemo(() => getIconOptions(), []); const [imagePreview, setImagePreview] = useState( value?.type === "image" ? value.value.startsWith("http") ? value.value : null : null, ); useEffect(() => { if (value?.type === "image") { if ( value.value.startsWith("http://") || value.value.startsWith("https://") ) { setImagePreview(value.value); } else if (/^\d+$/.test(value.value) && window.yatraAdmin?.apiUrl) { const apiUrl = window.yatraAdmin.apiUrl.replace("/yatra/v1", ""); fetch(`${apiUrl}/wp/v2/media/${value.value}`) .then((res) => res.json()) .then((data) => { if (data && data.source_url) { setImagePreview(data.source_url); } }) .catch(() => {}); } } else { setImagePreview(null); } }, [value]); const { openMediaLibrary } = useWordPressMedia({ title: __("Select or Upload Image", "yatra"), buttonText: __("Use this image", "yatra"), multiple: false, library: { type: "image" }, }); const sizeClasses = { sm: "w-8 h-8", md: "w-12 h-12", lg: "w-16 h-16", }; const iconSizeClasses = { sm: "w-4 h-4", md: "w-6 h-6", lg: "w-8 h-8", }; const filteredYatraIcons = useMemo(() => { const q = searchTerm.toLowerCase(); return yatraIconOptions.filter((icon) => { const matchesSearch = icon.label.toLowerCase().includes(q) || icon.name.toLowerCase().includes(q); const matchesCategory = selectedCategory === "all" || icon.category === selectedCategory; return matchesSearch && matchesCategory; }); }, [yatraIconOptions, searchTerm, selectedCategory]); const faSourceList = iconLibrary === "fa-regular" ? FA_FREE_REGULAR_PICKER : FA_FREE_SOLID_PICKER; const filteredFaIcons = useMemo(() => { const q = searchTerm.toLowerCase(); return faSourceList.filter( (row) => row.label.toLowerCase().includes(q) || row.name.toLowerCase().includes(q), ); }, [faSourceList, searchTerm]); const categories = useMemo( () => [ "all", ...Array.from(new Set(yatraIconOptions.map((icon) => icon.category))), ], [yatraIconOptions], ); const selectYatraIcon = (name: string) => { onChange({ type: "icon", value: name, provider: "yatra" }); setIsOpen(false); setSearchTerm(""); }; const selectFaIcon = (name: string, style: "fa-solid" | "fa-regular") => { onChange({ type: "icon", value: name, provider: style }); setIsOpen(false); setSearchTerm(""); }; const handleWordPressMediaSelect = useCallback(() => { openMediaLibrary((attachment) => { if (attachment && !Array.isArray(attachment)) { const attachmentId = String(attachment.id); setImagePreview(attachment.url); onChange({ type: "image", value: attachmentId }); setIsOpen(false); } }); }, [openMediaLibrary, onChange]); const handleRemoveImage = () => { setImagePreview(null); onChange(null); }; const handleImageUrlChange = (url: string) => { if (url.trim()) { setImagePreview(url); onChange({ type: "image", value: url.trim() }); } else { handleRemoveImage(); } }; const selectionSummary = (): string => { if (!value) { return __("Select Icon or Upload Image", "yatra"); } if (value.type === "image") { return __("Custom Image", "yatra"); } const p = value.provider ?? "yatra"; if (p === "fa-solid") { return `${__("Font Awesome Solid", "yatra")}: ${value.value}`; } if (p === "fa-regular") { return `${__("Font Awesome Regular", "yatra")}: ${value.value}`; } const meta = yatraIconOptions.find((o) => o.name === value.value); return `${__("Yatra", "yatra")}: ${meta?.label || value.value}`; }; const renderIconPreview = () => { if (!value || value.type !== "icon") { return ( ); } const p = value.provider ?? "yatra"; if (p === "fa-solid" || p === "fa-regular") { const prefix = p === "fa-regular" ? "fa-regular" : "fa-solid"; return (