import React, { useMemo } from 'react'; import { FaTimes } from 'react-icons/fa'; import { LANGUAGE_OPTIONS } from '../../data/locales'; import SearchableSelect from '../widgets/SearchableSelect'; /** Props for {@link LanguageMultiSelect}. */ interface LanguageMultiSelectProps { /** Currently-selected language codes (lowercased ISO 639-1). */ value: string[]; /** Fired with the next selection whenever the merchant adds or removes one. */ onChange: (next: string[]) => void; /** Disable the whole control while a generation is in flight. */ disabled?: boolean; /** Hard cap on how many languages can be selected. Hides the picker once hit. */ max?: number; /** Language codes to keep out of the dropdown (e.g. the fixed primary). */ exclude?: string[]; } /** * Pick one or more languages for article generation. Selected languages * render as removable chips; the searchable dropdown below adds another. * Picking two or more languages tells the backend to generate the topic in * each language at once and link them as a switchable "language version" set. * * Built on the same {@link SearchableSelect} and {@link LANGUAGE_OPTIONS} the * settings drawer uses, so the option list stays in lockstep with the brand * language picker. * * @param props {LanguageMultiSelectProps} Controlled multi-select props. * @returns {JSX.Element} The language multi-select. */ const LanguageMultiSelect = ({ value, onChange, disabled = false, max, exclude = [], }: LanguageMultiSelectProps): JSX.Element => { // Map code -> human label so chips show "Hungarian" not "hu". Falls back to // the raw code for any language not in the canonical list. const labelByCode = useMemo(() => { const map = new Map(); for (const option of LANGUAGE_OPTIONS) map.set(option.value, option.label); return map; }, []); // Hide already-selected and excluded languages from the dropdown so the // merchant can't add a duplicate or the fixed primary; the empty "value" // keeps the trigger in placeholder mode. const remainingOptions = useMemo( () => LANGUAGE_OPTIONS.filter( option => !value.includes(option.value) && !exclude.includes(option.value) ), [value, exclude] ); const atMax = typeof max === 'number' && value.length >= max; const handleAdd = (next: string): void => { const code = (next || '').trim().toLowerCase(); if (!code || value.includes(code) || atMax) return; onChange([...value, code]); }; const handleRemove = (code: string): void => { onChange(value.filter(entry => entry !== code)); }; return (
{value.length > 0 && (
{value.map(code => ( {labelByCode.get(code) ?? code.toUpperCase()} {!disabled && ( )} ))}
)} {!disabled && !atMax && ( )}
); }; export default LanguageMultiSelect;